Initial commit for combined ProjectKP

This commit is contained in:
raditarahman5-cloud
2026-06-28 15:14:51 +07:00
commit ac6c3473d4
203 changed files with 41848 additions and 0 deletions
@@ -0,0 +1,11 @@
@import 'tailwindcss';
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
@source '../../storage/framework/views/*.php';
@source '../**/*.blade.php';
@source '../**/*.js';
@theme {
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
}
@@ -0,0 +1 @@
//
@@ -0,0 +1,60 @@
@extends('admin.layouts.app')
@section('content')
{{-- Flex container untuk menarik konten ke tengah horizontal --}}
<div class="flex justify-center items-center w-full pb-20">
<div class="w-full max-w-lg"> {{-- max-w-lg membatasi lebar form supaya simetris --}}
<div class="mb-8 text-center">
<h1 class="text-3xl font-extrabold text-[#0D215C] tracking-tight">Tambah Petugas Baru</h1>
<p class="text-slate-500 mt-2 font-medium">Buat akun untuk pengawas lapangan</p>
</div>
<div class="bg-white rounded-[2.5rem] shadow-2xl shadow-slate-200/60 border border-slate-100 overflow-hidden">
<div class="p-8 md:p-12">
<form action="{{ route('admin.users.store') }}" method="POST" class="space-y-6">
@csrf
<div class="space-y-2">
<label class="text-[11px] font-black text-slate-400 uppercase tracking-[2px] ml-1">Nama Lengkap</label>
<input type="text" name="name"
class="w-full px-6 py-4 bg-[#F2F5FB] border-none rounded-2xl focus:ring-4 focus:ring-[#0D215C]/10 transition-all outline-none text-slate-700 placeholder:text-slate-300"
placeholder="Contoh: Budi Santoso" required>
</div>
<div class="space-y-2">
<label class="text-[11px] font-black text-slate-400 uppercase tracking-[2px] ml-1">Username</label>
<input type="text" name="username"
class="w-full px-6 py-4 bg-[#F2F5FB] border-none rounded-2xl focus:ring-4 focus:ring-[#0D215C]/10 transition-all outline-none text-slate-700 placeholder:text-slate-300"
placeholder="budi_petugas" required>
</div>
<div class="space-y-2">
<label class="text-[11px] font-black text-slate-400 uppercase tracking-[2px] ml-1">Password</label>
<input type="password" name="password"
class="w-full px-6 py-4 bg-[#F2F5FB] border-none rounded-2xl focus:ring-4 focus:ring-[#0D215C]/10 transition-all outline-none text-slate-700 placeholder:text-slate-300"
placeholder="Masukkan password" required>
</div>
<div class="pt-6">
<button type="submit"
class="w-full bg-[#0D215C] text-white font-bold py-5 rounded-2xl shadow-xl shadow-blue-900/20 hover:bg-[#081a45] transition-all transform active:scale-95">
Simpan Akun Petugas
</button>
</div>
</form>
</div>
</div>
<div class="mt-8 text-center">
<a href="{{ route('admin.users') }}" class="text-sm font-bold text-slate-400 hover:text-[#0D215C] transition-colors flex items-center justify-center">
<i data-lucide="arrow-left" class="w-4 h-4 mr-2"></i> KEMBALI KE DAFTAR
</a>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,913 @@
@extends('admin.layouts.app')
@section('content')
<style>
/* ══════════════════════════════════════════════
DISNAKER KALBAR ADMIN DASHBOARD
Professional Government Dashboard UI
══════════════════════════════════════════════ */
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
*, *::before, *::after { box-sizing: border-box; }
.d-wrap {
padding: 2rem 2.5rem 3rem;
max-width: 1440px;
margin: 0 auto;
font-family: 'Plus Jakarta Sans', sans-serif;
}
/* ── Page Header ─────────────────────────────── */
.page-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 1.75rem;
}
.page-header-left h2 {
font-size: 22px;
font-weight: 700;
color: #0D215C;
letter-spacing: -0.3px;
line-height: 1;
}
.page-header-left .subtitle {
font-size: 12.5px;
color: #94a3b8;
font-weight: 500;
margin-top: 5px;
display: flex;
align-items: center;
gap: 6px;
}
.status-dot {
width: 7px; height: 7px;
border-radius: 50%;
background: #22c55e;
display: inline-block;
box-shadow: 0 0 0 3px rgba(34,197,94,0.2);
animation: pulse-dot 2s infinite;
}
@keyframes pulse-dot {
0%,100% { box-shadow: 0 0 0 3px rgba(34,197,94,0.2); }
50% { box-shadow: 0 0 0 6px rgba(34,197,94,0.08); }
}
.page-header-right {
display: flex;
align-items: center;
gap: 10px;
}
.hdr-chip {
font-size: 11px;
font-weight: 600;
padding: 7px 18px;
border-radius: 50px;
letter-spacing: 0.4px;
display: flex;
align-items: center;
gap: 6px;
}
.hdr-chip.navy { background: #0D215C; color: #fff; box-shadow: 0 4px 14px rgba(13,33,92,0.22); }
.hdr-chip.light { background: #fff; color: #64748b; border: 1px solid #e2e8f0; }
.hdr-chip svg { flex-shrink: 0; }
/* ── Stat Cards ──────────────────────────────── */
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 18px;
margin-bottom: 1.75rem;
}
.s-card {
background: #fff;
border-radius: 20px;
padding: 1.5rem 1.6rem 1.4rem;
border: 1px solid #edf1f7;
position: relative;
overflow: hidden;
cursor: default;
transition: transform 0.22s cubic-bezier(.4,0,.2,1),
box-shadow 0.22s cubic-bezier(.4,0,.2,1);
}
.s-card:hover {
transform: translateY(-5px);
box-shadow: 0 16px 40px rgba(13,33,92,0.12);
}
.s-card::after {
content: '';
position: absolute;
bottom: 0; left: 0; right: 0;
height: 4px;
border-radius: 0 0 20px 20px;
opacity: 0.9;
}
.s-card.c-blue::after { background: linear-gradient(90deg,#3b82f6,#6366f1); }
.s-card.c-green::after { background: linear-gradient(90deg,#22c55e,#10b981); }
.s-card.c-yellow::after { background: linear-gradient(90deg,#f59e0b,#f97316); }
.s-card.c-red::after { background: linear-gradient(90deg,#64748b,#475569); }
.s-card::before {
content: '';
position: absolute;
top: -20px; right: -20px;
width: 100px; height: 100px;
border-radius: 50%;
opacity: 0.04;
}
.s-card.c-blue::before { background: #3b82f6; }
.s-card.c-green::before { background: #22c55e; }
.s-card.c-yellow::before { background: #f59e0b; }
.s-card.c-red::before { background: #64748b; }
.s-icon {
width: 44px; height: 44px;
border-radius: 12px;
display: flex; align-items: center; justify-content: center;
margin-bottom: 16px;
}
.s-icon.c-blue { background: #eff6ff; color: #3b82f6; }
.s-icon.c-green { background: #f0fdf4; color: #16a34a; }
.s-icon.c-yellow { background: #fffbeb; color: #d97706; }
.s-icon.c-red { background: #f8fafc; color: #475569; }
.s-icon svg { width: 20px; height: 20px; }
.s-num {
font-size: 36px;
font-weight: 700;
color: #0f172a;
letter-spacing: -2px;
line-height: 1;
}
.s-label {
font-size: 12px;
font-weight: 500;
color: #94a3b8;
margin-top: 5px;
letter-spacing: 0.3px;
}
.s-trend {
font-size: 11.5px;
font-weight: 500;
margin-top: 12px;
display: flex;
align-items: center;
gap: 4px;
color: #94a3b8;
}
.s-trend.up { color: #16a34a; }
.s-trend.down { color: #94a3b8; }
.s-trend.flat { color: #94a3b8; }
.s-trend svg { width: 13px; height: 13px; }
/* ── Main Content Grid ───────────────────────── */
.content-grid {
display: grid;
grid-template-columns: 1fr 360px;
gap: 20px;
align-items: start;
}
/* ── Generic Card ────────────────────────────── */
.g-card {
background: #fff;
border-radius: 20px;
padding: 1.5rem 1.6rem;
border: 1px solid #edf1f7;
box-shadow: 0 2px 12px rgba(13,33,92,0.04);
}
.g-card-title {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.2rem;
}
.g-card-title h3 {
font-size: 14px;
font-weight: 700;
color: #0D215C;
letter-spacing: -0.1px;
}
.g-card-title a {
font-size: 12px;
font-weight: 500;
color: #3b82f6;
text-decoration: none;
display: flex;
align-items: center;
gap: 4px;
transition: gap 0.18s;
}
.g-card-title a:hover { gap: 8px; }
/* ── Divider ─────────────────────────────────── */
.act-divider {
height: 1px;
background: #f1f5f9;
margin: 0 0 12px 0;
}
/* ── Filter Tabs ─────────────────────────────── */
.ftabs {
display: flex;
gap: 6px;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.ftab {
padding: 5px 15px;
border-radius: 50px;
font-size: 11px;
font-weight: 600;
cursor: pointer;
border: 1.5px solid transparent;
transition: all 0.15s;
user-select: none;
letter-spacing: 0.3px;
}
.ftab.on { background: #0D215C; color: #fff; border-color: #0D215C; }
.ftab.off { background: #f8fafc; color: #94a3b8; border-color: #e2e8f0; }
.ftab.off:hover { background: #eff6ff; color: #3b82f6; border-color: #bfdbfe; }
/* ── Activity Rows ───────────────────────────── */
.act-item {
display: flex;
align-items: center;
gap: 13px;
padding: 10px 10px;
border-radius: 12px;
cursor: pointer;
transition: background 0.15s, box-shadow 0.15s, transform 0.15s;
}
.act-item:hover {
background: #f8fafc;
box-shadow: 0 4px 16px rgba(13,33,92,0.06);
transform: translateX(2px);
}
.act-item:active { transform: scale(0.99); }
.act-ava {
width: 38px; height: 38px;
border-radius: 10px;
display: flex; align-items: center; justify-content: center;
font-size: 12px;
font-weight: 700;
color: #fff;
flex-shrink: 0;
}
.av-1 { background: linear-gradient(135deg,#3b82f6,#6366f1); }
.av-2 { background: linear-gradient(135deg,#14b8a6,#06b6d4); }
.av-3 { background: linear-gradient(135deg,#a855f7,#ec4899); }
.av-4 { background: linear-gradient(135deg,#f97316,#f59e0b); }
.av-5 { background: linear-gradient(135deg,#22c55e,#10b981); }
.act-body { flex: 1; min-width: 0; }
.act-name {
font-size: 13px;
font-weight: 600;
color: #1e293b;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.act-meta {
font-size: 11px;
color: #94a3b8;
font-weight: 400;
margin-top: 2px;
}
.pill {
font-size: 10px;
font-weight: 600;
padding: 4px 12px;
border-radius: 50px;
letter-spacing: 0.3px;
white-space: nowrap;
flex-shrink: 0;
}
.pill-ok { background: #dcfce7; color: #15803d; }
.pill-run { background: #dbeafe; color: #1d4ed8; }
.pill-del { background: #fee2e2; color: #b91c1c; }
.pill-pnd { background: #fef9c3; color: #92400e; }
.empty-box {
padding: 3.5rem 1rem;
text-align: center;
color: #cbd5e1;
}
.empty-box .ei {
width: 48px; height: 48px;
margin: 0 auto 12px;
display: flex; align-items: center; justify-content: center;
background: #f1f5f9;
border-radius: 14px;
color: #94a3b8;
}
.empty-box .ei svg { width: 22px; height: 22px; }
.empty-box p { font-size: 13px; font-weight: 500; color: #94a3b8; }
/* ── Modal ────────────────────────────────────── */
.modal-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(13,33,92,0.28);
backdrop-filter: blur(4px);
z-index: 999;
align-items: center;
justify-content: center;
animation: fadeIn 0.2s ease;
}
.modal-overlay.show { display: flex; }
@keyframes fadeIn { from { opacity:0; } to { opacity:1; } }
.modal-box {
background: #fff;
border-radius: 22px;
padding: 2rem;
width: 460px;
max-width: 95vw;
box-shadow: 0 30px 80px rgba(13,33,92,0.18);
animation: slideUp 0.25s cubic-bezier(.4,0,.2,1);
}
@keyframes slideUp {
from { opacity:0; transform:translateY(20px); }
to { opacity:1; transform:translateY(0); }
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.2rem;
}
.modal-header h4 {
font-size: 15px;
font-weight: 700;
color: #0D215C;
line-height: 1.4;
max-width: 85%;
}
.modal-close {
width: 30px; height: 30px;
border-radius: 50%;
background: #f1f5f9;
border: none;
cursor: pointer;
display: flex; align-items: center; justify-content: center;
color: #64748b;
transition: all 0.15s;
}
.modal-close:hover { background: #fee2e2; color: #ef4444; }
.modal-close svg { width: 14px; height: 14px; }
.modal-field {
display: flex;
gap: 10px;
padding: 10px 0;
border-bottom: 1px solid #f1f5f9;
font-size: 13px;
}
.modal-field:last-child { border-bottom: none; }
.modal-field .mf-label {
width: 120px;
flex-shrink: 0;
color: #94a3b8;
font-weight: 500;
font-size: 11.5px;
letter-spacing: 0.3px;
padding-top: 1px;
}
.modal-field .mf-value {
color: #1e293b;
font-weight: 500;
font-size: 13px;
}
/* ── Sidebar ─────────────────────────────────── */
.sidebar-col { display: flex; flex-direction: column; gap: 18px; }
/* Bar Chart */
.chart-bars {
display: flex;
align-items: flex-end;
gap: 8px;
height: 88px;
margin: 4px 0 8px;
}
.bar-wrap {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
gap: 6px;
cursor: pointer;
}
.bar-body {
width: 100%;
border-radius: 6px 6px 0 0;
background: #e0e7ff;
margin-top: auto;
transition: all 0.3s cubic-bezier(.4,0,.2,1);
position: relative;
}
.bar-wrap:hover .bar-body {
filter: brightness(0.9);
transform: scaleY(1.04);
transform-origin: bottom;
}
.bar-body::after {
content: attr(data-val);
position: absolute;
top: -28px;
left: 50%;
transform: translateX(-50%);
background: #0D215C;
color: #fff;
font-size: 10px;
font-weight: 600;
padding: 3px 8px;
border-radius: 6px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.15s;
}
.bar-wrap:hover .bar-body::after { opacity: 1; }
.bar-body.today { background: linear-gradient(180deg,#3b82f6 0%,#0D215C 100%); }
.bar-body.active { background: #93c5fd; }
.bar-lbl {
font-size: 10px;
font-weight: 500;
color: #94a3b8;
text-align: center;
}
.bar-lbl.today-lbl { color: #3b82f6; font-weight: 600; }
.chart-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
border-top: 1px solid #f1f5f9;
font-size: 12px;
color: #64748b;
font-weight: 400;
}
.chart-footer span { color: #94a3b8; }
.chart-footer strong { color: #0D215C; font-weight: 700; }
/* Progress */
.prog-item { margin-bottom: 14px; }
.prog-item:last-child { margin-bottom: 0; }
.prog-head { display: flex; justify-content: space-between; margin-bottom: 7px; }
.prog-head span { font-size: 12.5px; font-weight: 500; color: #334155; }
.prog-head strong { font-size: 12.5px; font-weight: 700; color: #0D215C; }
.prog-track { height: 8px; background: #f1f5f9; border-radius: 50px; overflow: hidden; }
.prog-fill { height: 100%; border-radius: 50px; transition: width 1.2s cubic-bezier(.4,0,.2,1); }
/* Top Users */
.usr-row {
display: flex;
align-items: center;
gap: 11px;
padding: 8px 10px;
border-radius: 12px;
transition: background 0.15s, box-shadow 0.15s;
cursor: default;
}
.usr-row:hover {
background: #f8fafc;
box-shadow: 0 2px 10px rgba(13,33,92,0.05);
}
.usr-rank {
width: 24px; height: 24px;
border-radius: 7px;
font-size: 11px;
font-weight: 700;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
.rank-1 { background: #fef9c3; color: #b45309; }
.rank-2 { background: #f1f5f9; color: #64748b; }
.rank-3 { background: #fff7ed; color: #c2410c; }
.rank-n { background: #f8fafc; color: #94a3b8; }
.usr-ava {
width: 32px; height: 32px;
border-radius: 9px;
background: linear-gradient(135deg,#0D215C,#2563eb);
color: #fff;
font-size: 10px;
font-weight: 700;
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
.usr-name { flex: 1; font-size: 12.5px; font-weight: 500; color: #334155; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.usr-count {
font-size: 11px;
font-weight: 600;
color: #3b82f6;
background: #eff6ff;
padding: 3px 11px;
border-radius: 50px;
flex-shrink: 0;
}
/* ── Animations ──────────────────────────────── */
@keyframes fadeUp {
from { opacity:0; transform:translateY(16px); }
to { opacity:1; transform:translateY(0); }
}
.s-card { animation: fadeUp 0.4s ease both; }
.s-card:nth-child(1) { animation-delay:.06s; }
.s-card:nth-child(2) { animation-delay:.12s; }
.s-card:nth-child(3) { animation-delay:.18s; }
.s-card:nth-child(4) { animation-delay:.24s; }
.content-grid { animation: fadeUp 0.4s .28s ease both; }
/* ── Responsive ──────────────────────────────── */
@media (max-width:1100px) { .content-grid { grid-template-columns:1fr; } }
@media (max-width:768px) {
.stats-grid { grid-template-columns:repeat(2,1fr); gap: 12px; }
.d-wrap { padding: 1rem 0.5rem; }
.page-header { flex-direction:column; align-items:flex-start; gap:12px; }
.page-header-right { flex-wrap: wrap; gap: 8px; }
.g-card { padding: 1.2rem; }
.act-item { gap: 10px; padding: 8px; }
.hdr-chip { padding: 6px 12px; }
}
@media (max-width:480px) {
.stats-grid { grid-template-columns:1fr; }
.d-wrap { padding: 0.8rem 0; }
.g-card { padding: 1rem; border-radius: 16px; }
.act-meta { font-size: 10px; }
.s-card { padding: 1.2rem; }
.act-item { flex-direction: column; align-items: flex-start; gap: 8px; }
.act-item .pill { align-self: flex-start; }
}
</style>
{{-- ═══════ MODAL (Detail Kegiatan) ═══════ --}}
<div class="modal-overlay" id="detailModal">
<div class="modal-box">
<div class="modal-header">
<h4 id="mdl-title"></h4>
<button class="modal-close" onclick="closeModal()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div id="mdl-body"></div>
</div>
</div>
<div class="d-wrap">
{{-- ── PAGE HEADER ── --}}
<div class="page-header">
<div class="page-header-left">
<h2>Dashboard Admin</h2>
<div class="subtitle">
<span class="status-dot"></span>
{{ \Carbon\Carbon::now()->timezone('Asia/Jakarta')->locale('id')->translatedFormat('l, d F Y') }}
&nbsp;·&nbsp; Sistem Online
</div>
</div>
<div class="page-header-right">
<span class="hdr-chip light">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" 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"/><polyline points="12 6 12 12 16 14"/></svg>
{{ \Carbon\Carbon::now()->timezone('Asia/Jakarta')->format('H:i') }} WIB
</span>
<span class="hdr-chip navy">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
Disnaker Kalbar
</span>
</div>
</div>
{{-- ── STAT CARDS ── --}}
<div class="stats-grid">
<div class="s-card c-blue">
<div class="s-icon c-blue">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2"/>
<rect x="9" y="3" width="6" height="4" rx="1"/>
<line x1="9" y1="12" x2="15" y2="12"/>
<line x1="9" y1="16" x2="13" y2="16"/>
</svg>
</div>
<div class="s-num">{{ $stats['total'] ?? 0 }}</div>
<div class="s-label">Total Kegiatan</div>
<div class="s-trend up">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
12% bulan ini
</div>
</div>
<div class="s-card c-green">
<div class="s-icon c-green">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
<polyline points="22 4 12 14.01 9 11.01"/>
</svg>
</div>
<div class="s-num">{{ $stats['selesai'] ?? 0 }}</div>
<div class="s-label">Kegiatan Selesai</div>
<div class="s-trend up">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
8% dari kemarin
</div>
</div>
<div class="s-card c-yellow">
<div class="s-icon c-yellow">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="2" x2="12" y2="6"/>
<line x1="12" y1="18" x2="12" y2="22"/>
<line x1="4.93" y1="4.93" x2="7.76" y2="7.76"/>
<line x1="16.24" y1="16.24" x2="19.07" y2="19.07"/>
<line x1="2" y1="12" x2="6" y2="12"/>
<line x1="18" y1="12" x2="22" y2="12"/>
<line x1="4.93" y1="19.07" x2="7.76" y2="16.24"/>
<line x1="16.24" y1="7.76" x2="19.07" y2="4.93"/>
</svg>
</div>
<div class="s-num">{{ $stats['proses'] ?? 0 }}</div>
<div class="s-label">Sedang Berjalan</div>
<div class="s-trend flat">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/></svg>
Sama seperti kemarin
</div>
</div>
<div class="s-card c-red">
<div class="s-icon c-red">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" 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"/>
</svg>
</div>
<div class="s-num">{{ $stats['users'] ?? 0 }}</div>
<div class="s-label">Pengguna Aktif</div>
<div class="s-trend down">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
3% minggu ini
</div>
</div>
</div>
{{-- ── MAIN GRID ── --}}
<div class="content-grid">
{{-- LEFT: Kegiatan Terbaru --}}
<div class="g-card">
<div class="g-card-title">
<h3>5 Kegiatan Terbaru</h3>
<a href="{{ route('admin.kegiatan.index') }}">Lihat Semua &rarr;</a>
</div>
<div class="ftabs">
<div class="ftab on" onclick="filterAct(this,'semua')">Semua</div>
<div class="ftab off" onclick="filterAct(this,'selesai')">Selesai</div>
<div class="ftab off" onclick="filterAct(this,'on_progres')">Berjalan</div>
<div class="ftab off" onclick="filterAct(this,'terlambat')">Terlambat</div>
<div class="ftab off" onclick="filterAct(this,'dibatalkan')">Dibatalkan</div>
</div>
<div class="act-divider"></div>
<div id="act-list">
@php
$avClasses = ['av-1','av-2','av-3','av-4','av-5'];
$pillMap = [
'selesai' => ['pill-ok', 'Selesai'],
'telah_ditinjau' => ['pill-ok', 'Ditinjau'],
'on_progres' => ['pill-run', 'Berjalan'],
'terlambat' => ['pill-del', 'Terlambat'],
'dibatalkan' => ['pill-del', 'Dibatalkan'],
'review' => ['pill-pnd', 'Review'],
'pending' => ['pill-pnd', 'Pending'],
];
@endphp
@forelse($activities ?? [] as $idx => $item)
@php
$st = strtolower($item->status ?? 'pending');
$pc = $pillMap[$st] ?? ['pill-pnd', ucfirst($st)];
$ac = $avClasses[$idx % 5];
$tgl = \Carbon\Carbon::parse($item->tanggal)->locale('id')->translatedFormat('d M Y');
$usr = e($item->user->name ?? 'Sistem');
$nm = e($item->nama_kegiatan);
@endphp
<div class="act-item"
data-status="{{ $st }}"
onclick="openModal(
'{{ addslashes($nm) }}',
'{{ addslashes($usr) }}',
'{{ $tgl }}',
'{{ $st }}',
'{{ addslashes(str_replace(["\r", "\n"], ["", "\\n"], $item->keterangan ?? '-')) }}',
'{{ addslashes(str_replace(["\r", "\n"], ["", "\\n"], $item->status_note ?? '')) }}',
'{{ addslashes($item->lokasi ?? '-') }}',
'{{ $item->lampiran ? rtrim(env('BACKEND_API_URL', 'http://127.0.0.1:8000'), '/api') . '/storage/' . $item->lampiran : '' }}'
)">
<div class="act-ava {{ $ac }}">{{ strtoupper(substr($item->user->name ?? 'U', 0, 2)) }}</div>
<div class="act-body">
<div class="act-name">{{ $nm }}</div>
<div class="act-meta">{{ $usr }} &bull; {{ $tgl }}</div>
</div>
<span class="pill {{ $pc[0] }}">{{ $pc[1] }}</span>
</div>
@empty
<div class="empty-box">
<div class="ei">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>
</div>
<p>Belum ada aktivitas kegiatan yang tercatat.</p>
</div>
@endforelse
</div>
</div>
{{-- RIGHT: Sidebar --}}
<div class="sidebar-col">
{{-- Weekly Chart --}}
<div class="g-card">
<div class="g-card-title" style="margin-bottom:.8rem">
<h3>Aktivitas Minggu Ini</h3>
@php $wTotal = array_sum($weeklyData ?? [0,0,0,0,0,0,0]); @endphp
<span class="pill pill-run">{{ $wTotal }} kegiatan</span>
</div>
@php
$days = ['Sen','Sel','Rab','Kam','Jum','Sab','Min'];
$wData = $weeklyData ?? [0,0,0,0,0,0,0];
$maxBar = max($wData) ?: 1;
$todayDI = (int)\Carbon\Carbon::now()->dayOfWeekIso - 1;
@endphp
<div class="chart-bars">
@foreach($days as $i => $d)
@php $pct = round(($wData[$i] / $maxBar) * 100); $isToday = $i === $todayDI; @endphp
<div class="bar-wrap">
<div class="bar-body {{ $isToday ? 'today' : ($wData[$i] > 0 ? 'active' : '') }}"
style="height:{{ max($pct, 8) }}%"
data-val="{{ $wData[$i] }} kegiatan">
</div>
<span class="bar-lbl {{ $isToday ? 'today-lbl' : '' }}">{{ $d }}</span>
</div>
@endforeach
</div>
<div class="chart-footer">
<span>Total minggu ini</span>
<strong>{{ $wTotal }} kegiatan</strong>
</div>
</div>
{{-- Division Progress --}}
<div class="g-card">
<div class="g-card-title" style="margin-bottom:.8rem">
<h3>Progres Divisi</h3>
</div>
{{-- FIX: Gunakan $divisionProgress dari controller, fallback jika tidak ada --}}
@php
$divs = $divisionProgress ?? [
['name' => 'Operasional', 'pct' => 78, 'clr' => 'linear-gradient(90deg,#3b82f6,#6366f1)'],
['name' => 'Keuangan', 'pct' => 64, 'clr' => 'linear-gradient(90deg,#22c55e,#10b981)'],
['name' => 'SDM', 'pct' => 91, 'clr' => 'linear-gradient(90deg,#f97316,#f59e0b)'],
['name' => 'IT', 'pct' => 55, 'clr' => 'linear-gradient(90deg,#a855f7,#ec4899)'],
];
@endphp
@foreach($divs as $dv)
<div class="prog-item">
<div class="prog-head">
<span>{{ $dv['name'] }}</span>
<strong>{{ $dv['pct'] ?? 0 }}%</strong>
</div>
<div class="prog-track">
<div class="prog-fill" style="width:{{ $dv['pct'] ?? 0 }}%;background:{{ $dv['clr'] ?? '#3b82f6' }}"></div>
</div>
</div>
@endforeach
</div>
{{-- Top Kontributor --}}
@if(!empty($topUsers) && count($topUsers))
<div class="g-card">
<div class="g-card-title" style="margin-bottom:.8rem">
<h3>Top Kontributor</h3>
</div>
@foreach($topUsers as $ri => $u)
@php
$rankCls = match($ri) { 0 => 'rank-1', 1 => 'rank-2', 2 => 'rank-3', default => 'rank-n' };
$medal = match($ri) {
0 => '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="#b45309" stroke="none"><circle cx="12" cy="8" r="6"/><path d="M15.477 12.89L17 22l-5-3-5 3 1.523-9.11"/></svg>',
1 => '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="#64748b" stroke="none"><circle cx="12" cy="8" r="6"/><path d="M15.477 12.89L17 22l-5-3-5 3 1.523-9.11"/></svg>',
2 => '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="#c2410c" stroke="none"><circle cx="12" cy="8" r="6"/><path d="M15.477 12.89L17 22l-5-3-5 3 1.523-9.11"/></svg>',
default => $ri + 1
};
@endphp
<div class="usr-row">
<div class="usr-rank {{ $rankCls }}">{!! $medal !!}</div>
<div class="usr-ava">{{ strtoupper(substr($u->name, 0, 2)) }}</div>
<span class="usr-name">{{ $u->name }}</span>
{{-- FIX: Ganti kegiatan_count activities_count (sesuai withCount('activities')) --}}
<span class="usr-count">{{ $u->activities_count ?? 0 }} Lap.</span>
</div>
@endforeach
</div>
@endif
</div>{{-- /sidebar --}}
</div>{{-- /content-grid --}}
</div>{{-- /d-wrap --}}
<script>
/* ── Filter Tabs ─────────────────── */
function filterAct(el, status) {
document.querySelectorAll('.ftab').forEach(t => {
t.classList.remove('on');
t.classList.add('off');
});
el.classList.add('on');
el.classList.remove('off');
document.querySelectorAll('#act-list .act-item').forEach(row => {
row.style.display = (status === 'semua' || row.dataset.status === status) ? 'flex' : 'none';
});
}
/* ── Modal ───────────────────────── */
const pillLabels = {
selesai: '<span class="pill pill-ok">Selesai</span>',
on_progres: '<span class="pill pill-run">Berjalan</span>',
terlambat: '<span class="pill pill-del">Terlambat</span>',
dibatalkan: '<span class="pill pill-del">Dibatalkan</span>',
review: '<span class="pill pill-pnd">Review</span>',
pending: '<span class="pill pill-pnd">Pending</span>'
};
function openModal(nama, user, tgl, status, ket, statusNote, lokasi, lampiranUrl) {
document.getElementById('mdl-title').textContent = nama;
let lampiranHtml = '';
if (lampiranUrl) {
lampiranHtml = `
<div class="modal-field" style="margin-top: 15px; grid-column: span 2;">
<span class="mf-label">Lampiran Foto/Dokumen</span>
<div style="margin-top: 8px;">
<img src="${lampiranUrl}" alt="Lampiran" style="max-width: 100%; max-height: 400px; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
</div>
</div>`;
}
document.getElementById('mdl-body').innerHTML = `
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
<div class="modal-field">
<span class="mf-label">Pegawai Ditugaskan</span>
<span class="mf-value">${user}</span>
</div>
<div class="modal-field">
<span class="mf-label">Tanggal</span>
<span class="mf-value">${tgl}</span>
</div>
<div class="modal-field">
<span class="mf-label">Lokasi Tugas</span>
<span class="mf-value">${lokasi}</span>
</div>
<div class="modal-field">
<span class="mf-label">Status</span>
<span class="mf-value">${pillLabels[status] || status}</span>
</div>
<div class="modal-field" style="grid-column: span 2;">
<span class="mf-label">Deskripsi Laporan (Keterangan)</span>
<span class="mf-value" style="white-space: pre-wrap; line-height: 1.5;">${ket || '—'}</span>
</div>
${statusNote ? `
<div class="modal-field" style="grid-column: span 2; background: #eff6ff; padding: 12px; border-radius: 8px;">
<span class="mf-label" style="color: #2563eb; margin-bottom: 4px; display: block;">Catatan Status (Node Petugas)</span>
<span class="mf-value" style="white-space: pre-wrap; line-height: 1.5; color: #1e3a8a;">${statusNote}</span>
</div>
` : ''}
${lampiranHtml}
</div>
`;
document.getElementById('detailModal').classList.add('show');
}
function closeModal() {
document.getElementById('detailModal').classList.remove('show');
}
document.getElementById('detailModal').addEventListener('click', function(e) {
if (e.target === this) closeModal();
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeModal();
});
</script>
@endsection
@@ -0,0 +1,212 @@
@extends('admin.layouts.app')
@section('content')
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
*, *::before, *::after { box-sizing: border-box; }
body, * { font-family: 'Plus Jakarta Sans', sans-serif; }
.eu-wrap {
padding: 2rem 2.5rem 3rem;
max-width: 640px;
margin: 0 auto;
}
.eu-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 2rem;
}
.eu-title { font-size: 22px; font-weight: 700; color: #0D215C; }
.eu-sub { font-size: 13px; color: #94a3b8; margin-top: 4px; }
.btn-back {
padding: 8px 18px;
border-radius: 10px;
background: #eef2ff;
color: #3730a3;
font-size: 13px;
font-weight: 600;
text-decoration: none;
transition: .2s;
}
.btn-back:hover { background: #dbeafe; color: #1d4ed8; }
.eu-card {
background: #fff;
border: 1px solid #edf1f7;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(13,33,92,.05);
}
.eu-card-header {
padding: 1.2rem 1.5rem;
border-bottom: 1px solid #f1f5f9;
background: #f8fafc;
display: flex;
align-items: center;
gap: 10px;
}
.eu-card-header h3 { font-size: 14px; font-weight: 700; color: #0D215C; margin: 0; }
.eu-body { padding: 1.5rem; }
.form-group { margin-bottom: 1.2rem; }
.form-label {
display: block;
font-size: 13px;
font-weight: 700;
color: #374151;
margin-bottom: 7px;
}
.form-input, .form-select-field {
width: 100%;
padding: 11px 14px;
border: 1.5px solid #e2e8f0;
border-radius: 12px;
font-size: 14px;
outline: none;
color: #0f172a;
background: #fff;
transition: border .2s, box-shadow .2s;
}
.form-input:focus, .form-select-field:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59,130,246,.1);
}
.form-hint {
font-size: 11px;
color: #94a3b8;
margin-top: 5px;
}
.pw-wrap { position: relative; }
.pw-wrap .form-input { padding-right: 44px; }
.pw-toggle {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: #94a3b8;
padding: 4px;
display: flex;
align-items: center;
}
.pw-toggle:hover { color: #3b82f6; }
.btn-submit {
width: 100%;
padding: 13px;
margin-top: .5rem;
background: #0D215C;
color: #fff;
border: none;
border-radius: 12px;
font-size: 14px;
font-weight: 700;
cursor: pointer;
transition: .2s;
box-shadow: 0 4px 14px rgba(13,33,92,.2);
}
.btn-submit:hover { background: #1e3a8a; transform: translateY(-1px); }
.alert-error {
background: #fee2e2;
color: #b91c1c;
padding: 12px 16px;
border-radius: 10px;
margin-bottom: 1rem;
font-size: 13px;
}
</style>
<div class="eu-wrap">
<div class="eu-header">
<div>
<div class="eu-title">Edit Pengguna</div>
<div class="eu-sub">Perbarui informasi akun pengguna</div>
</div>
<a href="{{ route('admin.users') }}" class="btn-back"> Kembali</a>
</div>
<div class="eu-card">
<div class="eu-card-header">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0D215C" 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"/></svg>
<h3>Form Edit Pengguna</h3>
</div>
<div class="eu-body">
@if($errors->any())
<div class="alert-error">
@foreach($errors->all() as $e) <div> {{ $e }}</div> @endforeach
</div>
@endif
@if(session('error'))
<div class="alert-error"> {{ session('error') }}</div>
@endif
<form action="{{ route('admin.users.update', $user->id) }}" method="POST">
@csrf
<div class="form-group">
<label class="form-label" for="name">Nama Lengkap</label>
<input type="text" id="name" name="name" class="form-input"
value="{{ old('name', $user->name) }}" placeholder="Nama lengkap pengguna" required>
</div>
<div class="form-group">
<label class="form-label" for="username">Username</label>
<input type="text" id="username" name="username" class="form-input"
value="{{ old('username', $user->username) }}" placeholder="Username login" required>
</div>
<div class="form-group">
<label class="form-label" for="jabatan">Jabatan</label>
<input type="text" id="jabatan" name="jabatan" class="form-input"
value="{{ old('jabatan', $user->jabatan ?? '') }}" placeholder="Jabatan pengguna (opsional)">
</div>
<div class="form-group">
<label class="form-label" for="role">Role / Hak Akses</label>
<select id="role" name="role" class="form-select-field">
<option value="user" {{ old('role', $user->role) == 'user' ? 'selected' : '' }}>Petugas Lapangan</option>
<option value="admin" {{ old('role', $user->role) == 'admin' ? 'selected' : '' }}>Administrator (Kasi)</option>
<option value="superadmin" {{ old('role', $user->role) == 'superadmin' ? 'selected' : '' }}>Super Admin (Kabid)</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="password">Password Baru</label>
<div class="pw-wrap">
<input type="password" id="password" name="password" class="form-input"
placeholder="Kosongkan jika tidak ingin mengubah">
<button type="button" class="pw-toggle" onclick="togglePassword('password','eyeIconPw')">
<svg id="eyeIconPw" xmlns="http://www.w3.org/2000/svg" width="18" height="18" 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"/></svg>
</button>
</div>
<div class="form-hint">Minimal 6 karakter. Kosongkan jika tidak ingin mengubah password.</div>
</div>
<button type="submit" class="btn-submit">Simpan Perubahan</button>
</form>
</div>
</div>
</div>
<script>
function togglePassword(fieldId, iconId) {
const field = document.getElementById(fieldId);
const icon = document.getElementById(iconId);
if (field.type === 'password') {
field.type = 'text';
icon.innerHTML = '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>';
} else {
field.type = 'password';
icon.innerHTML = '<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"/>';
}
}
</script>
@endsection
@@ -0,0 +1,242 @@
@extends('admin.layouts.app')
@section('content')
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
*, *::before, *::after { box-sizing: border-box; }
body, * { font-family: 'Plus Jakarta Sans', sans-serif; }
.detail-wrap {
padding: 2rem 2.5rem 3rem;
max-width: 900px;
margin: 0 auto;
}
.detail-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 2rem;
}
.detail-title { font-size: 22px; font-weight: 700; color: #0D215C; }
.detail-sub { font-size: 13px; color: #94a3b8; margin-top: 4px; }
.btn-back {
padding: 8px 18px;
border-radius: 10px;
background: #eef2ff;
color: #3730a3;
font-size: 13px;
font-weight: 600;
text-decoration: none;
transition: all .2s;
}
.btn-back:hover { background: #dbeafe; color: #1d4ed8; }
.detail-card {
background: #fff;
border: 1px solid #edf1f7;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(13,33,92,.05);
margin-bottom: 1.5rem;
}
.detail-card-header {
padding: 1.2rem 1.5rem;
border-bottom: 1px solid #f1f5f9;
background: #f8fafc;
display: flex;
align-items: center;
gap: 10px;
}
.detail-card-header h3 {
font-size: 14px;
font-weight: 700;
color: #0D215C;
margin: 0;
}
.detail-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
}
.detail-field {
padding: 1rem 1.5rem;
border-bottom: 1px solid #f1f5f9;
display: flex;
flex-direction: column;
gap: 4px;
}
.detail-field:nth-child(odd) { border-right: 1px solid #f1f5f9; }
.detail-field.full {
grid-column: 1 / -1;
border-right: none;
}
.df-label {
font-size: 11px;
font-weight: 700;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: .5px;
}
.df-value {
font-size: 14px;
font-weight: 600;
color: #0f172a;
}
.pill {
display: inline-flex;
font-size: 11px;
font-weight: 700;
padding: 5px 14px;
border-radius: 50px;
letter-spacing: .3px;
}
.pill-ok { background: #dcfce7; color: #15803d; }
.pill-run { background: #dbeafe; color: #1d4ed8; }
.pill-rev { background: #fef9c3; color: #92400e; }
.pill-del { background: #fee2e2; color: #b91c1c; }
.petugas-list {
padding: 1rem 1.5rem;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.petugas-chip {
display: flex;
align-items: center;
gap: 8px;
background: #f1f5f9;
border-radius: 10px;
padding: 8px 14px;
font-size: 13px;
font-weight: 500;
color: #334155;
}
.petugas-ava {
width: 28px; height: 28px;
border-radius: 8px;
background: linear-gradient(135deg, #0D215C, #2563eb);
color: #fff;
font-size: 10px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
}
.action-bar {
display: flex;
gap: 12px;
margin-top: 1.5rem;
}
.action-btn {
padding: 10px 22px;
border-radius: 12px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
border: none;
cursor: pointer;
transition: .2s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-edit { background: #0D215C; color: #fff; box-shadow: 0 4px 12px rgba(13,33,92,.2); }
.btn-edit:hover { background: #1e3a8a; }
.btn-batal { background: #fee2e2; color: #b91c1c; }
.btn-batal:hover { background: #fecaca; }
</style>
<div class="detail-wrap">
{{-- HEADER --}}
<div class="detail-header">
<div>
<div class="detail-title">Detail Kegiatan</div>
<div class="detail-sub">Informasi lengkap penugasan lapangan</div>
</div>
<a href="{{ route('admin.kegiatan.index') }}" class="btn-back"> Kembali</a>
</div>
{{-- INFO UTAMA --}}
<div class="detail-card">
<div class="detail-card-header">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0D215C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2"/><rect x="9" y="3" width="6" height="4" rx="1"/></svg>
<h3>Informasi Penugasan</h3>
</div>
<div class="detail-grid">
<div class="detail-field">
<div class="df-label">Nomor Surat</div>
<div class="df-value">{{ $activity->nomor_surat ?? '-' }}</div>
</div>
<div class="detail-field">
<div class="df-label">Status</div>
<div class="df-value">
@php
$pillMap = [
'selesai' => ['pill-ok', 'Selesai'],
'on_progres' => ['pill-run', 'Sedang Berjalan'],
'telah_ditinjau' => ['pill-rev', 'Telah Ditinjau'],
'dibatalkan' => ['pill-del', 'Dibatalkan'],
];
$pc = $pillMap[$activity->status] ?? ['pill-run', ucfirst($activity->status)];
@endphp
<span class="pill {{ $pc[0] }}">{{ $pc[1] }}</span>
</div>
</div>
<div class="detail-field full">
<div class="df-label">Nama Kegiatan</div>
<div class="df-value">{{ $activity->nama_kegiatan }}</div>
</div>
<div class="detail-field">
<div class="df-label">Tanggal Mulai</div>
<div class="df-value">{{ \Carbon\Carbon::parse($activity->tanggal)->locale('id')->translatedFormat('d F Y') }}</div>
</div>
<div class="detail-field">
<div class="df-label">Tanggal Selesai</div>
<div class="df-value">
{{ $activity->tanggal_selesai ? \Carbon\Carbon::parse($activity->tanggal_selesai)->locale('id')->translatedFormat('d F Y') : '-' }}
</div>
</div>
<div class="detail-field">
<div class="df-label">Penanggung Jawab</div>
<div class="df-value">{{ optional($activity->user)->name ?? '-' }}</div>
</div>
<div class="detail-field">
<div class="df-label">Terakhir Diperbarui</div>
<div class="df-value">{{ \Carbon\Carbon::parse($activity->updated_at)->locale('id')->translatedFormat('d F Y, H:i') }}</div>
</div>
</div>
</div>
{{-- DAFTAR PETUGAS --}}
<div class="detail-card">
<div class="detail-card-header">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0D215C" 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"/></svg>
<h3>Petugas yang Ditugaskan</h3>
</div>
<div class="petugas-list">
@forelse($activity->petugas ?? [] as $p)
@php $nm = is_array($p) ? ($p['name'] ?? '-') : ($p->name ?? '-'); @endphp
<div class="petugas-chip">
<div class="petugas-ava">{{ strtoupper(substr($nm, 0, 2)) }}</div>
{{ $nm }}
</div>
@empty
<span style="color:#94a3b8;font-size:13px;">Belum ada petugas yang ditetapkan.</span>
@endforelse
</div>
</div>
</div>
@endsection
@@ -0,0 +1,220 @@
@extends('admin.layouts.app')
@section('content')
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
*, *::before, *::after { box-sizing: border-box; }
body, * { font-family: 'Plus Jakarta Sans', sans-serif; }
.edit-wrap {
padding: 2rem 2.5rem 3rem;
max-width: 680px;
margin: 0 auto;
}
.edit-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 2rem;
}
.edit-title { font-size: 22px; font-weight: 700; color: #0D215C; }
.edit-sub { font-size: 13px; color: #94a3b8; margin-top: 4px; }
.btn-back {
padding: 8px 18px;
border-radius: 10px;
background: #eef2ff;
color: #3730a3;
font-size: 13px;
font-weight: 600;
text-decoration: none;
transition: all .2s;
}
.btn-back:hover { background: #dbeafe; color: #1d4ed8; }
.edit-card {
background: #fff;
border: 1px solid #edf1f7;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(13,33,92,.05);
}
.edit-card-header {
padding: 1.2rem 1.5rem;
border-bottom: 1px solid #f1f5f9;
background: #f8fafc;
display: flex;
align-items: center;
gap: 10px;
}
.edit-card-header h3 {
font-size: 14px;
font-weight: 700;
color: #0D215C;
margin: 0;
}
.edit-body { padding: 1.5rem; }
.info-row {
display: flex;
flex-direction: column;
gap: 4px;
padding: 12px 0;
border-bottom: 1px solid #f1f5f9;
margin-bottom: 4px;
}
.info-row:last-of-type { border-bottom: none; }
.info-label {
font-size: 11px;
font-weight: 700;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: .5px;
}
.info-value {
font-size: 15px;
font-weight: 600;
color: #0f172a;
}
.form-group { margin-top: 1.5rem; }
.form-label {
display: block;
font-size: 13px;
font-weight: 700;
color: #374151;
margin-bottom: 8px;
}
.form-select {
width: 100%;
padding: 12px 16px;
border: 1.5px solid #e2e8f0;
border-radius: 12px;
font-size: 14px;
outline: none;
background: #fff;
cursor: pointer;
color: #0f172a;
transition: border .2s;
appearance: auto;
}
.form-select:focus { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59,130,246,.1); }
.status-info {
margin-top: 10px;
padding: 10px 14px;
background: #fffbeb;
border-radius: 10px;
font-size: 12px;
color: #92400e;
border: 1px solid #fde68a;
}
.btn-submit {
width: 100%;
padding: 14px;
margin-top: 1.5rem;
background: #0D215C;
color: #fff;
border: none;
border-radius: 12px;
font-size: 14px;
font-weight: 700;
cursor: pointer;
transition: .2s;
box-shadow: 0 4px 14px rgba(13,33,92,.2);
}
.btn-submit:hover { background: #1e3a8a; transform: translateY(-1px); }
.pill {
display: inline-flex;
font-size: 11px;
font-weight: 700;
padding: 4px 12px;
border-radius: 50px;
}
.pill-ok { background: #dcfce7; color: #15803d; }
.pill-run { background: #dbeafe; color: #1d4ed8; }
.pill-rev { background: #fef9c3; color: #92400e; }
.pill-del { background: #fee2e2; color: #b91c1c; }
</style>
<div class="edit-wrap">
{{-- HEADER --}}
<div class="edit-header">
<div>
<div class="edit-title">Ubah Status Kegiatan</div>
<div class="edit-sub">Perbarui status kemajuan kegiatan lapangan</div>
</div>
<a href="{{ route('admin.kegiatan.show', $activity->id) }}" class="btn-back"> Kembali</a>
</div>
{{-- FORM CARD --}}
<div class="edit-card">
<div class="edit-card-header">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0D215C" 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"/></svg>
<h3>Form Edit Status</h3>
</div>
<div class="edit-body">
{{-- ALERT --}}
@if($errors->any())
<div style="background:#fee2e2;color:#b91c1c;padding:12px 16px;border-radius:10px;margin-bottom:1rem;font-size:13px;">
@foreach($errors->all() as $e) <div> {{ $e }}</div> @endforeach
</div>
@endif
{{-- INFO KEGIATAN --}}
<div class="info-row">
<div class="info-label">Nomor Surat</div>
<div class="info-value">{{ $activity->nomor_surat ?? '-' }}</div>
</div>
<div class="info-row">
<div class="info-label">Nama Kegiatan</div>
<div class="info-value">{{ $activity->nama_kegiatan }}</div>
</div>
<div class="info-row">
<div class="info-label">Status Saat Ini</div>
<div class="info-value">
@php
$pillMap = [
'selesai' => ['pill-ok', 'Selesai'],
'on_progres' => ['pill-run', 'Sedang Berjalan'],
'telah_ditinjau' => ['pill-rev', 'Telah Ditinjau'],
'dibatalkan' => ['pill-del', 'Dibatalkan'],
];
$pc = $pillMap[$activity->status] ?? ['pill-run', ucfirst($activity->status)];
@endphp
<span class="pill {{ $pc[0] }}">{{ $pc[1] }}</span>
</div>
</div>
{{-- FORM --}}
<form action="{{ route('admin.kegiatan.update', $activity->id) }}" method="POST">
@csrf
@method('POST')
<div class="form-group">
<label class="form-label" for="status">Status Baru</label>
<select name="status" id="status" class="form-select">
<option value="on_progres" {{ $activity->status == 'on_progres' ? 'selected' : '' }}>Sedang Berjalan</option>
<option value="selesai" {{ $activity->status == 'selesai' ? 'selected' : '' }}>Selesai</option>
<option value="telah_ditinjau" {{ $activity->status == 'telah_ditinjau' ? 'selected' : '' }}>Telah Ditinjau</option>
</select>
<div class="status-info">
⚠️ Perubahan status bersifat permanen dan akan tercatat dalam riwayat sistem.
</div>
</div>
<button type="submit" class="btn-submit">Simpan Perubahan Status</button>
</form>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,329 @@
@extends('admin.layouts.app')
@section('content')
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
*, *::before, *::after { box-sizing: border-box; }
.keg-wrap {
padding: 2rem 2.5rem 3rem;
max-width: 1440px;
margin: 0 auto;
font-family: 'Plus Jakarta Sans', sans-serif;
}
/* ── Header ─── */
.keg-topbar {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 1.75rem;
}
.keg-title { font-size: 22px; font-weight: 700; color: #0D215C; }
.keg-sub { font-size: 12.5px; color: #94a3b8; margin-top: 4px; }
.keg-btn-back {
padding: 8px 18px;
border-radius: 10px;
background: #eef2ff;
color: #3730a3;
font-size: 13px;
font-weight: 600;
text-decoration: none;
transition: all .2s;
}
.keg-btn-back:hover { background: #dbeafe; color: #1d4ed8; }
/* ── Stats Strip ─── */
.keg-stats {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 16px;
margin-bottom: 1.5rem;
}
.kstat {
background: #fff;
border: 1px solid #edf1f7;
border-radius: 16px;
padding: 1.2rem 1.4rem;
display: flex;
align-items: center;
gap: 14px;
}
.kstat-icon {
width: 42px; height: 42px;
border-radius: 12px;
display: flex; align-items: center; justify-content: center;
}
.kstat-icon.blue { background: #eff6ff; color: #3b82f6; }
.kstat-icon.green { background: #f0fdf4; color: #16a34a; }
.kstat-icon.yellow { background: #fffbeb; color: #d97706; }
.kstat-num { font-size: 28px; font-weight: 700; color: #0f172a; line-height: 1; }
.kstat-label { font-size: 12px; color: #94a3b8; margin-top: 3px; font-weight: 500; }
/* ── Search + Filter ─── */
.keg-filter-bar {
display: flex;
gap: 12px;
align-items: center;
margin-bottom: 1.2rem;
flex-wrap: wrap;
}
.keg-search {
flex: 1;
min-width: 200px;
padding: 9px 14px;
border: 1.5px solid #e2e8f0;
border-radius: 10px;
font-size: 13px;
outline: none;
transition: border .2s;
}
.keg-search:focus { border-color: #3b82f6; }
.keg-select {
padding: 9px 14px;
border: 1.5px solid #e2e8f0;
border-radius: 10px;
font-size: 13px;
outline: none;
background: #fff;
cursor: pointer;
}
.keg-filter-btn {
padding: 9px 20px;
background: #0D215C;
color: #fff;
border: none;
border-radius: 10px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: .2s;
}
.keg-filter-btn:hover { background: #1e3a8a; }
/* ── Table Card ─── */
.keg-card {
background: #fff;
border: 1px solid #edf1f7;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(13,33,92,.04);
}
.keg-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
.keg-table thead { background: #f8fafc; }
.keg-table thead th {
padding: 14px 18px;
text-align: left;
font-size: 11px;
font-weight: 700;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: .5px;
}
.keg-table tbody td {
padding: 14px 18px;
border-top: 1px solid #f1f5f9;
vertical-align: middle;
color: #334155;
}
.keg-table tbody tr:hover { background: #f8fafc; }
.pill {
font-size: 10px;
font-weight: 700;
padding: 4px 12px;
border-radius: 50px;
letter-spacing: .3px;
white-space: nowrap;
}
.pill-ok { background: #dcfce7; color: #15803d; }
.pill-run { background: #dbeafe; color: #1d4ed8; }
.pill-rev { background: #fef9c3; color: #92400e; }
.pill-del { background: #fee2e2; color: #b91c1c; }
.act-btn {
padding: 6px 14px;
border-radius: 8px;
font-size: 11px;
font-weight: 700;
text-decoration: none;
border: none;
cursor: pointer;
transition: .15s;
display: inline-flex;
align-items: center;
gap: 4px;
}
.btn-view { background: #eff6ff; color: #2563eb; }
.btn-view:hover { background: #dbeafe; }
.btn-edit-k { background: #f0fdf4; color: #15803d; }
.btn-edit-k:hover { background: #dcfce7; }
.btn-del-k { background: #fff1f2; color: #be123c; }
.btn-del-k:hover { background: #fee2e2; }
.pg-wrap { padding: 16px 18px; border-top: 1px solid #f1f5f9; }
.empty-row td {
text-align: center;
padding: 3rem;
color: #94a3b8;
font-size: 13px;
}
/* ── Responsive ─── */
@media (max-width: 768px) {
.keg-wrap { padding: 1rem; }
.keg-topbar { flex-direction: column; align-items: flex-start; gap: 12px; }
.keg-stats { grid-template-columns: 1fr; gap: 12px; }
.keg-filter-bar { flex-direction: column; align-items: stretch; }
.keg-search, .keg-select, .keg-filter-btn { width: 100%; }
}
</style>
<div class="keg-wrap">
{{-- ALERTS --}}
@if(session('success'))
<div style="background:#dcfce7;color:#166534;padding:12px 18px;border-radius:12px;margin-bottom:1.2rem;font-size:13px;font-weight:600;">
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div style="background:#fee2e2;color:#b91c1c;padding:12px 18px;border-radius:12px;margin-bottom:1.2rem;font-size:13px;font-weight:600;">
{{ session('error') }}
</div>
@endif
{{-- TOPBAR --}}
<div class="keg-topbar">
<div>
<div class="keg-title">Daftar Kegiatan</div>
<div class="keg-sub">Monitor dan kelola seluruh kegiatan lapangan</div>
</div>
<a href="{{ route('admin.dashboard') }}" class="keg-btn-back"> Kembali ke Dashboard</a>
</div>
{{-- STATS --}}
@php
$totalAll = $allItems->count();
$totalSelesai = $allItems->where('status','selesai')->count();
$totalProses = $allItems->where('status','on_progres')->count();
@endphp
<div class="keg-stats">
<div class="kstat">
<div class="kstat-icon blue">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2"/><rect x="9" y="3" width="6" height="4" rx="1"/></svg>
</div>
<div>
<div class="kstat-num">{{ $totalAll }}</div>
<div class="kstat-label">Total Kegiatan</div>
</div>
</div>
<div class="kstat">
<div class="kstat-icon green">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
</div>
<div>
<div class="kstat-num">{{ $totalSelesai }}</div>
<div class="kstat-label">Selesai</div>
</div>
</div>
<div class="kstat">
<div class="kstat-icon yellow">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
</div>
<div>
<div class="kstat-num">{{ $totalProses }}</div>
<div class="kstat-label">Sedang Berjalan</div>
</div>
</div>
</div>
{{-- FILTER BAR --}}
<form method="GET" action="{{ route('admin.kegiatan.index') }}" class="keg-filter-bar">
<input type="text" name="search" class="keg-search" placeholder="Cari nama kegiatan / penanggung jawab..." value="{{ request('search') }}">
<select name="status" class="keg-select">
<option value="semua" {{ request('status','semua')=='semua' ? 'selected':'' }}>Semua Status</option>
<option value="on_progres" {{ request('status')=='on_progres' ? 'selected':'' }}>Sedang Berjalan</option>
<option value="selesai" {{ request('status')=='selesai' ? 'selected':'' }}>Selesai</option>
<option value="telah_ditinjau" {{ request('status')=='telah_ditinjau' ? 'selected':'' }}>Telah Ditinjau</option>
</select>
<button type="submit" class="keg-filter-btn">Cari</button>
@if(request('search') || request('status'))
<a href="{{ route('admin.kegiatan.index') }}" class="keg-btn-back" style="padding:9px 16px;font-size:12px;">Reset</a>
@endif
</form>
{{-- TABLE --}}
<div class="keg-card">
<div style="overflow-x: auto; width: 100%;">
<table class="keg-table" style="min-width: 700px;">
<thead>
<tr>
<th>#</th>
<th>Nama Kegiatan</th>
<th>Penanggung Jawab</th>
<th>Tanggal</th>
<th>Status</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse($activities as $i => $item)
@php
$namaUser = optional($item->user)->name ?? 'User Tidak Ada';
$inisial = collect(explode(' ', $namaUser))
->take(2)
->map(fn($w) => strtoupper(substr($w,0,1)))
->join('');
$pillMap = [
'selesai' => ['pill-ok', 'Selesai'],
'on_progres' => ['pill-run', 'Berjalan'],
'telah_ditinjau' => ['pill-rev', 'Ditinjau'],
'dibatalkan' => ['pill-del', 'Dibatalkan'],
];
$pc = $pillMap[$item->status] ?? ['pill-run', ucfirst($item->status)];
@endphp
<tr>
<td>{{ $activities->firstItem() + $i }}</td>
<td><strong>{{ $item->nama_kegiatan }}</strong></td>
<td>
<div style="display:flex;align-items:center;gap:8px;">
<span style="background:#e0e7ff;color:#3730a3;width:30px;height:30px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;">{{ $inisial }}</span>
{{ $namaUser }}
</div>
</td>
<td>{{ \Carbon\Carbon::parse($item->tanggal)->format('d M Y') }}</td>
<td><span class="pill {{ $pc[0] }}">{{ $pc[1] }}</span></td>
<td>
<div style="display:flex;gap:6px;">
<a href="{{ route('admin.kegiatan.show', $item->id) }}" class="act-btn btn-view">Lihat</a>
</div>
</td>
</tr>
@empty
<tr class="empty-row">
<td colspan="6">
<div style="display:flex;flex-direction:column;align-items:center;gap:8px;color:#94a3b8;">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>
Tidak ada data kegiatan yang ditemukan.
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="pg-wrap">{{ $activities->links() }}</div>
</div>
</div>
@endsection
@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard Admin Disnaker Prov. Kalimantan Barat</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; }
body {
font-family: 'Outfit', sans-serif;
background: #F2F5FB;
color: #334155;
margin: 0;
padding: 0;
}
main {
min-height: 100vh;
}
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: #f1f5f9; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
</style>
</head>
<body>
@include('admin.layouts.navbar')
<main class="pt-10 px-4">
{{-- Yield inilah panggung untuk konten kamu --}}
@yield('content')
</main>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
lucide.createIcons();
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('[onclick^="return confirm"]').forEach(function(btn) {
const match = btn.getAttribute('onclick').match(/confirm\('([^']+)'\)/);
if (match) {
const message = match[1];
btn.removeAttribute('onclick');
btn.addEventListener('click', function(e) {
e.preventDefault();
const form = btn.closest('form');
Swal.fire({
title: 'Konfirmasi',
text: message,
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3b82f6',
cancelButtonColor: '#64748b',
confirmButtonText: 'Ya, Lanjutkan',
cancelButtonText: 'Batal',
reverseButtons: true,
customClass: {
confirmButton: 'rounded-xl',
cancelButton: 'rounded-xl mr-2'
}
}).then((result) => {
if (result.isConfirmed) {
if (form) {
form.submit();
} else if(btn.getAttribute('href')) {
window.location.href = btn.getAttribute('href');
}
}
});
});
}
});
});
</script>
</body>
</html>
@@ -0,0 +1,146 @@
@php
$role = session('user')['role'] ?? '';
$dashboardRoute = $role === 'superadmin' ? route('admin.superadmin.dashboard') : route('admin.dashboard');
$usersRoute = $role === 'superadmin' ? route('admin.superadmin.user.index') : route('admin.users');
$penugasanRoute = $role === 'superadmin' ? route('admin.superadmin.kegiatan.create') : route('admin.kegiatan.index');
$isDashboard = request()->routeIs('*.dashboard');
$isUsers = request()->routeIs('*.user*') || request()->routeIs('*.users*');
$isPenugasan = request()->routeIs('*.kegiatan.*');
$activeStyle = "bg-[#0D215C] text-white";
$inactiveStyle = "text-slate-500 bg-transparent hover:bg-slate-100 hover:text-[#0D215C]";
$roleVal = session('user')['role'] ?? 'Administrator';
if ($roleVal === 'admin') {
$roleVal = 'Administrator';
} elseif ($roleVal === 'superadmin') {
$roleVal = 'Super Admin';
} else {
$roleVal = 'Petugas';
}
@endphp
<nav class="bg-white border-b border-slate-200 shadow-[0_1px_12px_rgba(13,33,92,0.06)] sticky top-0 z-50">
<div class="max-w-[1440px] mx-auto px-4 md:px-6 lg:px-8">
<div class="flex justify-between items-center h-[66px]">
{{-- Logo & Brand --}}
<div class="flex items-center gap-2 md:gap-3">
<img src="{{ asset('Kalimantan-Barat-Logo-Vector.png') }}"
alt="Logo Kalbar"
class="w-9 md:w-[46px] h-auto object-contain">
<div class="border-l-2 border-slate-200 pl-2 md:pl-3">
<p class="text-[11px] md:text-[13.5px] font-bold text-[#0D215C] tracking-tight leading-tight m-0">
Dinas Tenaga Kerja dan Transmigrasi
</p>
<p class="text-[8px] md:text-[10px] font-medium text-slate-400 tracking-[1.8px] uppercase mt-0.5 m-0">
Provinsi Kalimantan Barat
</p>
</div>
</div>
<!-- Hamburger Button (Mobile) -->
<div class="flex md:hidden">
<button type="button" id="admin-menu-btn" class="text-slate-500 hover:text-[#0D215C] focus:outline-none p-2 rounded-md hover:bg-slate-100 transition-colors">
<i data-lucide="menu" class="w-6 h-6"></i>
</button>
</div>
{{-- Nav + User (Desktop) --}}
<div class="hidden md:flex items-center gap-2">
<div class="flex items-center gap-1 mr-2">
<a href="{{ $dashboardRoute }}" class="text-[11.5px] font-semibold tracking-[0.4px] px-[18px] py-2 rounded-lg flex items-center gap-[7px] transition-all duration-200 {{ $isDashboard ? $activeStyle : $inactiveStyle }}">
<i data-lucide="layout-dashboard" class="w-3.5 h-3.5"></i> Dashboard
</a>
<a href="{{ $usersRoute }}" class="text-[11.5px] font-semibold tracking-[0.4px] px-[18px] py-2 rounded-lg flex items-center gap-[7px] transition-all duration-200 {{ $isUsers ? $activeStyle : $inactiveStyle }}">
<i data-lucide="users" class="w-3.5 h-3.5"></i> Kelola Pengguna
</a>
<a href="{{ $penugasanRoute }}" class="text-[11.5px] font-semibold tracking-[0.4px] px-[18px] py-2 rounded-lg flex items-center gap-[7px] transition-all duration-200 {{ $isPenugasan ? $activeStyle : $inactiveStyle }}">
<i data-lucide="clipboard-list" class="w-3.5 h-3.5"></i> Penugasan
</a>
</div>
<div class="w-px h-7 bg-slate-200 mx-1"></div>
<div class="flex items-center gap-2.5">
<div class="text-right">
<p class="text-[13px] font-semibold text-slate-900 leading-none m-0">
{{ session('user')['name'] ?? 'User' }}
</p>
<p class="text-[10px] font-medium text-slate-400 uppercase tracking-[1.2px] mt-1 m-0">
{{ $roleVal }}
</p>
</div>
<div class="w-9 h-9 rounded-lg bg-gradient-to-br from-[#0D215C] to-blue-800 text-white flex items-center justify-center font-bold text-xs tracking-[0.5px]">
{{ strtoupper(substr(session('user')['name'] ?? 'US',0,2)) }}
</div>
<form method="POST" action="{{ route('logout') }}" class="m-0">
@csrf
<button type="submit" class="w-9 h-9 rounded-lg bg-slate-50 text-slate-400 border border-slate-200 cursor-pointer flex items-center justify-center transition-all duration-200 hover:bg-rose-50 hover:text-rose-500 hover:border-rose-200" title="Keluar dari Sistem">
<i data-lucide="log-out" class="w-3.5 h-3.5"></i>
</button>
</form>
</div>
</div>
</div>
</div>
<!-- Mobile Menu Panel -->
<div id="admin-mobile-menu" class="hidden md:hidden bg-white border-t border-slate-100 shadow-xl absolute w-full left-0 pb-4">
<div class="px-4 py-3 flex flex-col gap-2">
<a href="{{ $dashboardRoute }}" class="text-[13px] font-semibold tracking-[0.4px] px-4 py-3 rounded-lg flex items-center gap-3 transition-all duration-200 {{ $isDashboard ? $activeStyle : $inactiveStyle }}">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> Dashboard
</a>
<a href="{{ $usersRoute }}" class="text-[13px] font-semibold tracking-[0.4px] px-4 py-3 rounded-lg flex items-center gap-3 transition-all duration-200 {{ $isUsers ? $activeStyle : $inactiveStyle }}">
<i data-lucide="users" class="w-4 h-4"></i> Kelola Pengguna
</a>
<a href="{{ $penugasanRoute }}" class="text-[13px] font-semibold tracking-[0.4px] px-4 py-3 rounded-lg flex items-center gap-3 transition-all duration-200 {{ $isPenugasan ? $activeStyle : $inactiveStyle }}">
<i data-lucide="clipboard-list" class="w-4 h-4"></i> Penugasan
</a>
<div class="h-px w-full bg-slate-100 my-1"></div>
<div class="flex items-center justify-between px-2 py-2">
<div class="flex items-center gap-3">
<div class="w-9 h-9 rounded-lg bg-gradient-to-br from-[#0D215C] to-blue-800 text-white flex items-center justify-center font-bold text-xs tracking-[0.5px]">
{{ strtoupper(substr(session('user')['name'] ?? 'US',0,2)) }}
</div>
<div>
<p class="text-[13px] font-semibold text-slate-900 leading-none m-0">
{{ session('user')['name'] ?? 'User' }}
</p>
<p class="text-[10px] font-medium text-slate-400 uppercase tracking-[1.2px] mt-1 m-0">
{{ $roleVal }}
</p>
</div>
</div>
<form method="POST" action="{{ route('logout') }}" class="m-0">
@csrf
<button type="submit" class="w-9 h-9 rounded-lg bg-slate-50 text-slate-400 border border-slate-200 cursor-pointer flex items-center justify-center transition-all duration-200 hover:bg-rose-50 hover:text-rose-500 hover:border-rose-200" title="Keluar dari Sistem">
<i data-lucide="log-out" class="w-4 h-4"></i>
</button>
</form>
</div>
</div>
</div>
</nav>
<script>
document.addEventListener('DOMContentLoaded', function() {
const btn = document.getElementById('admin-menu-btn');
const menu = document.getElementById('admin-mobile-menu');
if(btn && menu) {
btn.addEventListener('click', function(e) {
e.stopPropagation();
menu.classList.toggle('hidden');
lucide.createIcons();
});
document.addEventListener('click', function(e) {
if(!menu.contains(e.target) && !btn.contains(e.target)) {
menu.classList.add('hidden');
}
});
}
});
</script>
@@ -0,0 +1,268 @@
@extends('admin.layouts.app')
@section('content')
<style>
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
*, *::before, *::after { box-sizing: border-box; }
body, * { font-family: 'Plus Jakarta Sans', sans-serif; }
.user-wrap { padding: 2rem 2.5rem 3rem; max-width: 1200px; margin: 0 auto; }
/* ALERTS */
.alert { padding: 12px 18px; border-radius: 12px; margin-bottom: 1.2rem; font-size: 13px; font-weight: 600; }
.alert-success { background: #dcfce7; color: #166534; }
.alert-error { background: #fee2e2; color: #b91c1c; }
/* HEADER */
.user-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.user-title h2 { font-size: 26px; font-weight: 800; color: #0f172a; margin: 0; }
.user-title p { font-size: 13px; color: #94a3b8; margin-top: 5px; }
.top-btn { display: flex; gap: 12px; }
.btn-ui {
border: none;
padding: 10px 18px;
border-radius: 12px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
transition: .2s;
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
.btn-dashboard { background: #eef2ff; color: #3730a3; }
.btn-dashboard:hover { background: #dbeafe; transform: translateY(-2px); }
.btn-add { background: #0D215C; color: #fff; box-shadow: 0 4px 14px rgba(13,33,92,.2); }
.btn-add:hover { background: #1e3a8a; transform: translateY(-2px); }
/* STATS */
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin-bottom: 2rem;
}
.stat-card {
background: #fff;
border-radius: 18px;
padding: 1.2rem 1.4rem;
border: 1px solid #edf1f7;
transition: .25s;
cursor: default;
box-shadow: 0 2px 8px rgba(13,33,92,.04);
}
.stat-card:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(13,33,92,.1); }
.stat-label { font-size: 11px; font-weight: 700; color: #94a3b8; text-transform: uppercase; letter-spacing: .5px; margin-bottom: 8px; }
.stat-number { font-size: 34px; font-weight: 800; color: #0f172a; }
/* TABLE */
.user-card {
background: #fff;
border-radius: 20px;
border: 1px solid #edf1f7;
overflow: hidden;
box-shadow: 0 2px 12px rgba(13,33,92,.04);
}
.user-card-header {
padding: 1.2rem 1.5rem;
border-bottom: 1px solid #f1f5f9;
background: #f8fafc;
}
.user-card-header h3 { font-size: 15px; font-weight: 700; color: #0D215C; margin: 0; }
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
thead { background: #f8fafc; }
thead th {
padding: 14px 18px;
font-size: 11px;
text-transform: uppercase;
color: #94a3b8;
text-align: left;
font-weight: 700;
letter-spacing: .5px;
}
tbody td {
padding: 15px 18px;
border-top: 1px solid #f1f5f9;
vertical-align: middle;
font-size: 13px;
color: #334155;
}
tbody tr:hover { background: #f8fafc; }
.user-info { display: flex; align-items: center; gap: 12px; }
.avatar {
width: 40px; height: 40px;
border-radius: 12px;
background: linear-gradient(135deg, #0D215C, #2563eb);
color: #fff;
display: flex; align-items: center; justify-content: center;
font-weight: 700;
font-size: 13px;
flex-shrink: 0;
}
.user-name { font-weight: 700; color: #0f172a; font-size: 14px; }
.user-id { font-size: 11px; color: #94a3b8; margin-top: 2px; }
.role-badge {
padding: 5px 14px;
border-radius: 50px;
font-size: 11px;
font-weight: 700;
letter-spacing: .3px;
}
.role-superadmin { background: #fef3c7; color: #92400e; }
.role-admin { background: #dbeafe; color: #1d4ed8; }
.role-user { background: #dcfce7; color: #166534; }
.action-group { display: flex; gap: 8px; }
.action-btn {
border: none;
padding: 7px 14px;
border-radius: 10px;
font-size: 11px;
font-weight: 700;
cursor: pointer;
text-decoration: none;
transition: .15s;
display: inline-flex;
align-items: center;
gap: 5px;
}
.btn-edit { background: #dbeafe; color: #2563eb; }
.btn-edit:hover { background: #bfdbfe; }
.btn-delete { background: #fee2e2; color: #dc2626; }
.btn-delete:hover { background: #fecaca; }
/* RESPONSIVE */
@media (max-width: 768px) {
.user-wrap { padding: 1rem 0.5rem; }
.user-header { flex-direction: column; align-items: flex-start; gap: 16px; margin-bottom: 1.5rem; }
.top-btn { flex-wrap: wrap; width: 100%; }
.top-btn .btn-ui { flex: 1; justify-content: center; text-align: center; }
.stats-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 1.5rem; }
.user-card-header { padding: 1rem; }
}
@media (max-width: 480px) {
.stats-grid { grid-template-columns: 1fr; }
.user-title h2 { font-size: 22px; }
.user-card { border-radius: 16px; }
}
</style>
<div class="user-wrap">
{{-- ALERTS --}}
@if(session('success'))
<div class="alert alert-success"> {{ session('success') }}</div>
@endif
@if(session('error'))
<div class="alert alert-error"> {{ session('error') }}</div>
@endif
{{-- HEADER --}}
<div class="user-header">
<div class="user-title">
<h2>Manajemen Pengguna</h2>
<p>Kelola seluruh akun dan hak akses pengguna sistem</p>
</div>
<div class="top-btn">
<a href="{{ route('admin.dashboard') }}" class="btn-ui btn-dashboard"> Dashboard</a>
<a href="{{ route('admin.users.create') }}" class="btn-ui btn-add">+ Tambah Pengguna</a>
</div>
</div>
{{-- STATS --}}
@php
$usersCol = collect($users);
$totalUsers = $usersCol->count();
$totalAdmin = $usersCol->where('role', 'admin')->count();
$totalPetugas = $usersCol->where('role', 'user')->count();
@endphp
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">Total Pengguna</div>
<div class="stat-number">{{ $totalUsers }}</div>
</div>
<div class="stat-card">
<div class="stat-label">Administrator</div>
<div class="stat-number">{{ $totalAdmin }}</div>
</div>
<div class="stat-card">
<div class="stat-label">Petugas Lapangan</div>
<div class="stat-number">{{ $totalPetugas }}</div>
</div>
</div>
{{-- TABLE --}}
<div class="user-card">
<div class="user-card-header">
<h3>Daftar Pengguna Sistem</h3>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Pengguna</th>
<th>Username</th>
<th>Jabatan</th>
<th>Role</th>
<th>Terdaftar</th>
</tr>
</thead>
<tbody>
@forelse($users as $user)
@php $u = is_array($user) ? (object)$user : $user; @endphp
<tr>
<td>
<div class="user-info">
<div class="avatar">{{ strtoupper(substr($u->name ?? '-', 0, 2)) }}</div>
<div>
<div class="user-name">{{ $u->name ?? '-' }}</div>
<div class="user-id">ID #{{ $u->id ?? '-' }}</div>
</div>
</div>
</td>
<td>{{ $u->username ?? '-' }}</td>
<td>{{ $u->jabatan ?? '-' }}</td>
<td>
@if(($u->role ?? '') == 'superadmin')
<span class="role-badge role-superadmin">Super Admin</span>
@elseif(($u->role ?? '') == 'admin')
<span class="role-badge role-admin">Administrator</span>
@else
<span class="role-badge role-user">Petugas</span>
@endif
</td>
<td>
@if(!empty($u->created_at))
{{ \Carbon\Carbon::parse($u->created_at)->format('d M Y') }}
@else
-
@endif
</td>
</tr>
@empty
<tr>
<td colspan="5" style="text-align:center;padding:2.5rem;color:#94a3b8;font-size:13px;">
Belum ada data pengguna.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,253 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - Disnaker Kalbar</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&display=swap" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
<style>
:root{
--primary:#2b3f8f;
--primary-dark:#1f2f6b;
--bg:#f4f6fb;
--muted:#6b7280;
--border:#e5e7eb;
}
*{margin:0;padding:0;box-sizing:border-box;font-family:'Inter',sans-serif;}
body{height:100vh;display:flex;}
.left{
width:50%;
background:
linear-gradient(rgba(0,0,0,0.6), rgba(0,0,0,0.8)),
url("{{ asset('bg-login.jpeg') }}");
background-size:cover;
background-position:center;
color:white;
padding:70px;
display:flex;
flex-direction:column;
justify-content:space-between;
}
.brand{display:flex;align-items:center;gap:15px;}
.brand img{height:100px;}
.brand-text{font-size:15px;font-weight:700;}
.hero{margin-top:-20px;max-width:520px;}
.hero h1{
font-size:52px;
font-weight:800;
line-height:1.3;
}
.hero h1::after{
content:"";
display:block;
width:80px;
height:4px;
background:#60a5fa;
margin-top:15px;
border-radius:10px;
}
.hero p{
margin-top:20px;
color:#dbeafe;
line-height:1.8;
}
.footer{
font-size:12px;
letter-spacing:2px;
}
.right{
width:50%;
background:var(--bg);
display:flex;
justify-content:center;
align-items:center;
}
.card{
width:100%;
max-width:420px;
}
.card h2{
font-size:34px;
margin-bottom:8px;
}
.card p{
color:var(--muted);
margin-bottom:25px;
}
.input-group{margin-bottom:18px;}
.input-group label{
font-size:12px;
color:var(--muted);
font-weight:600;
}
.input-box{
display:flex;
align-items:center;
border:1px solid var(--border);
border-radius:12px;
padding:14px;
margin-top:6px;
background:white;
}
.input-box i{
margin-right:10px;
color:#9ca3af;
}
.input-box input{
border:none;
outline:none;
width:100%;
font-size:14px;
}
.btn{
width:100%;
padding:14px;
background:var(--primary);
color:white;
border:none;
border-radius:12px;
font-weight:600;
cursor:pointer;
}
.btn:hover{background:var(--primary-dark);}
.error{
background:#fee2e2;
color:#991b1b;
padding:10px;
border-radius:8px;
margin-bottom:15px;
font-size:13px;
}
.copy{
text-align:center;
font-size:12px;
margin-top:25px;
color:#9ca3af;
}
.toggle-password{cursor:pointer;}
@media (max-width: 768px) {
body {
flex-direction: column;
height: auto;
min-height: 100vh;
}
.left {
width: 100%;
padding: 40px 20px;
min-height: 350px;
gap: 30px;
}
.hero h1 {
font-size: 36px;
}
.right {
width: 100%;
padding: 40px 20px;
flex: 1;
}
}
</style>
</head>
<body>
<div class="left">
<div class="brand">
<img src="{{ asset('Kalimantan-Barat-Logo-Vector.png') }}">
<div class="brand-text">
DINAS TENAGA KERJA DAN TRANSMIGRASI<br>
<span style="font-weight:400;font-size:12px;">PROVINSI KALIMANTAN BARAT</span>
</div>
</div>
<div class="hero">
<h1>Sistem Monitoring<br>Aktivitas Pegawai</h1>
<p>
Platform terintegrasi untuk pelaporan aktivitas, pemantauan kinerja pegawai,
serta tata kelola administrasi yang transparan, akuntabel, dan profesional.
</p>
</div>
<div class="footer">
TRANSPARANSI AKUNTABILITAS INTEGRITAS
</div>
</div>
<div class="right">
<div class="card">
<h2>Selamat Datang</h2>
<p>Silakan masuk untuk mengakses panel monitoring pegawai.</p>
@if(session('error'))
<div class="error">{{ session('error') }}</div>
@endif
<!-- 🔥 FIX UTAMA DI SINI -->
<form method="POST" action="{{ route('login.user') }}">
@csrf
<div class="input-group">
<label>USERNAME</label>
<div class="input-box">
<i class="fas fa-user"></i>
<input type="text" name="username" value="{{ old('username') }}" required>
</div>
</div>
<div class="input-group">
<label>KATA SANDI</label>
<div class="input-box">
<i class="fas fa-lock"></i>
<input type="password" name="password" id="password" required>
<i class="fas fa-eye toggle-password" onclick="togglePassword()"></i>
</div>
</div>
<button type="submit" class="btn">Masuk ke Sistem </button>
</form>
<div class="copy">
© 2026 DINAS TENAGA KERJA DAN TRANSMIGRASI <br>
PROVINSI KALIMANTAN BARAT
</div>
</div>
</div>
<script>
function togglePassword() {
const input = document.getElementById('password');
input.type = input.type === 'password' ? 'text' : 'password';
}
</script>
</body>
</html>
@@ -0,0 +1,334 @@
@extends('admin.layouts.app')
@section('content')
{{-- STYLES --}}
<style>
/* Reset & Base */
:root {
--bg-main: #f4f7fb;
--card-bg: #ffffff;
--text-primary: #0f172a;
--text-secondary: #475569;
--text-muted: #94a3b8;
--text-faint: #cbd5e1;
--border-color: #e2e8f0;
--blue-dark: #0D215C;
--blue-mid: #2563eb;
--blue-pale: #bfdbfe;
--blue-ultra: #eff6ff;
--green: #10b981;
--red: #ef4444;
--amber: #f59e0b;
}
.sa-container {
padding: 30px;
background: var(--bg-main);
min-height: calc(100vh - 70px);
font-family: 'Outfit', 'Segoe UI', sans-serif;
}
.sa-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
}
.sa-title-wrap {
display: flex;
flex-direction: column;
}
.sa-title-wrap h1 {
font-size: 32px;
font-weight: 900;
color: #000;
margin: 0;
text-transform: uppercase;
letter-spacing: -1px;
position: relative;
display: inline-block;
}
.sa-title-wrap h1::after {
content: "";
display: block;
width: 50px;
height: 4px;
background: #000;
margin-top: 5px;
}
.btn-back {
text-decoration: none;
font-size: 14px;
color: var(--blue-mid);
font-weight: 600;
background: #fff;
padding: 8px 16px;
border-radius: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
transition: all 0.3s ease;
}
.btn-back:hover {
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
/* Cards Grid */
.news-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
.news-card {
background: var(--card-bg);
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0,0,0,0.04);
transition: all 0.3s ease;
display: flex;
flex-direction: column;
border: 1px solid rgba(226,232,240,0.6);
position: relative;
}
.news-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 30px rgba(0,0,0,0.08);
}
.news-card a:hover .news-title {
color: var(--blue-mid);
}
.news-image {
width: 100%;
height: 180px;
object-fit: cover;
background-color: #e2e8f0;
}
.news-content {
padding: 20px;
display: flex;
flex-direction: column;
flex-grow: 1;
}
.news-meta {
display: flex;
align-items: center;
gap: 12px;
font-size: 12px;
color: var(--text-muted);
font-weight: 600;
margin-bottom: 12px;
text-transform: uppercase;
}
.news-meta svg {
width: 14px;
height: 14px;
opacity: 0.7;
}
.meta-item {
display: flex;
align-items: center;
gap: 4px;
}
.news-title {
font-size: 18px;
font-weight: 800;
color: var(--text-primary);
line-height: 1.4;
margin: 0 0 12px 0;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.news-footer {
margin-top: auto;
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 16px;
border-top: 1px solid var(--border-color);
}
.status-badge {
font-size: 11px;
font-weight: 700;
padding: 4px 10px;
border-radius: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.status-badge.selesai { background: #ecfdf5; color: #059669; }
.status-badge.proses { background: #eff6ff; color: #2563eb; }
.status-badge.batal { background: #fef2f2; color: #dc2626; }
.btn-restore {
background: transparent;
border: none;
color: var(--blue-mid);
font-weight: 600;
font-size: 13px;
cursor: pointer;
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border-radius: 8px;
transition: all 0.2s;
}
.btn-restore:hover {
background: var(--blue-ultra);
}
.empty-state {
grid-column: 1 / -1;
text-align: center;
padding: 60px 20px;
background: #fff;
border-radius: 20px;
border: 1px dashed var(--border-color);
color: var(--text-muted);
}
@media (max-width: 768px) {
.sa-container {
padding: 15px;
}
.sa-header {
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.btn-back {
align-self: flex-start;
}
.news-grid {
grid-template-columns: 1fr;
}
}
</style>
{{-- ICONS --}}
<svg width="0" height="0" style="position:absolute; display:none;">
<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" ry="2"></rect>
<line x1="16" y1="2" x2="16" y2="6"></line>
<line x1="8" y1="2" x2="8" y2="6"></line>
<line x1="3" y1="10" x2="21" y2="10"></line>
</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"></path>
<circle cx="12" cy="12" r="3"></circle>
</symbol>
<symbol id="ic-restore" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/>
<path d="M3 3v5h5"/>
</symbol>
</svg>
<div class="sa-container">
<div class="sa-header">
<div class="sa-title-wrap">
<h1>Arsip Laporan</h1>
</div>
<a href="{{ route('admin.superadmin.dashboard') }}" class="btn-back">&larr; Kembali ke Dashboard</a>
</div>
@if(session('success'))
<div style="padding:14px 18px; background:#ecfdf5; border:1px solid #a7f3d0; border-radius:12px; color:#047857; font-size:14px; font-weight:600; margin-bottom:24px; display:flex; align-items:center; gap:10px;">
<svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"></path></svg>
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div style="padding:14px 18px; background:#fef2f2; border:1px solid #fecaca; border-radius:12px; color:#dc2626; font-size:14px; font-weight:600; margin-bottom:24px; display:flex; align-items:center; gap:10px;">
<svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"></path></svg>
{{ session('error') }}
</div>
@endif
<div class="news-grid">
@forelse($activities as $act)
@php
// Generate a consistent dummy views count based on ID
$views = ($act->id * 17) % 1000 + 50;
// Array of default placeholder images for variety
$placeholders = [
'https://images.unsplash.com/photo-1454165804606-c3d57bc86b40?q=80&w=600&auto=format&fit=crop', // office/planning
'https://images.unsplash.com/photo-1517048676732-d65bc937f952?q=80&w=600&auto=format&fit=crop', // teamwork
'https://images.unsplash.com/photo-1552664730-d307ca884978?q=80&w=600&auto=format&fit=crop', // meeting
'https://images.unsplash.com/photo-1507537297725-24a1c029d3ca?q=80&w=600&auto=format&fit=crop', // paper/desk
'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?q=80&w=600&auto=format&fit=crop' // tech/research
];
$imgSrc = $placeholders[$act->id % count($placeholders)];
@endphp
<div class="news-card">
<a href="{{ route('admin.superadmin.kegiatan.show', $act->id) }}" style="text-decoration: none; color: inherit; display: flex; flex-direction: column; flex-grow: 1;">
<img src="{{ $imgSrc }}" alt="Laporan Image" class="news-image" loading="lazy">
<div class="news-content" style="padding-bottom: 0; flex-grow: 1;">
<div class="news-meta">
<div class="meta-item">
<svg><use href="#ic-calendar"/></svg>
<span>{{ \Carbon\Carbon::parse($act->tanggal)->translatedFormat('d M Y') }}</span>
</div>
<span>&bull;</span>
<div class="meta-item">
<svg><use href="#ic-eye"/></svg>
<span>{{ $views }}</span>
</div>
</div>
<h3 class="news-title" title="{{ $act->nama_kegiatan }}">{{ $act->nama_kegiatan }}</h3>
</div>
</a>
<div class="news-content" style="padding-top: 10px; flex-grow: 0;">
<div class="news-footer">
<span class="status-badge {{ $act->status == 'selesai' ? 'selesai' : ($act->status == 'dibatalkan' ? 'batal' : 'proses') }}">
{{ strtoupper(str_replace('_', ' ', $act->status)) }}
</span>
<form action="{{ route('admin.superadmin.kegiatan.archive', $act->id) }}" method="POST" style="margin: 0;">
@csrf
<button type="submit" class="btn-restore" title="Kembalikan Laporan">
<svg width="16" height="16"><use href="#ic-restore"/></svg>
Restore
</button>
</form>
</div>
</div>
</div>
@empty
<div class="empty-state">
<svg width="64" height="64" style="color:var(--text-faint); margin-bottom:15px;" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 002-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg>
<h3>Belum ada arsip laporan</h3>
<p>Laporan yang diarsipkan akan muncul di sini.</p>
</div>
@endforelse
</div>
@if($activities->hasPages())
<div style="margin-top:40px; display:flex; justify-content:center;">
{{ $activities->links('pagination::bootstrap-4') }}
</div>
@endif
</div>
@endsection
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,125 @@
@extends('admin.layouts.app')
@section('content')
<style>
.page-container { padding: 40px 20px; background: #f4f7fb; min-height: calc(100vh - 70px); font-family: 'Outfit', 'Segoe UI', sans-serif; display: flex; flex-direction: column; align-items: center; }
.form-card { background: #fff; border-radius: 24px; box-shadow: 0 10px 40px rgba(0,0,0,0.03); width: 100%; max-width: 600px; padding: 35px 40px; box-sizing: border-box; }
.date-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 35px; }
.page-title { font-size: 28px; font-weight: 800; color: #0f172a; margin: 0 0 8px; letter-spacing: -0.5px; }
@media (max-width: 768px) {
.page-container { padding: 20px 15px !important; }
.form-card { padding: 25px 20px !important; border-radius: 16px !important; }
.date-grid { grid-template-columns: 1fr !important; gap: 15px !important; margin-bottom: 25px !important; }
.page-title { font-size: 24px !important; }
}
</style>
<div class="page-container">
{{-- HEADER --}}
<div style="text-align:center; margin-bottom:30px;">
<h1 class="page-title">Buat Penugasan Baru</h1>
<p style="margin:0; color:#64748b; font-size:15px; font-weight:500;">Berikan instruksi tugas kepada pegawai lapangan</p>
</div>
@if(session('error'))
<div style="width:100%; max-width:600px; margin-bottom:20px; padding:14px 18px; background:#fff1f2; border:1px solid #fecdd3; border-radius:12px; color:#be123c; font-size:14px; font-weight:600; display:flex; align-items:center; gap:8px;">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><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"/></svg>
{{ session('error') }}
</div>
@endif
{{-- FORM CARD --}}
<div class="form-card">
<form action="{{ route('admin.superadmin.kegiatan.store') }}" method="POST">
@csrf
@if ($errors->any())
<div style="margin-bottom:20px; padding:14px 18px; background:#fff1f2; border:1px solid #fecdd3; border-radius:12px;">
<p style="font-weight:700; color:#be123c; margin:0 0 8px; font-size:13px;">Terdapat kesalahan input:</p>
<ul style="margin:0; padding-left:18px; color:#be123c; font-size:13px;">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div style="margin-bottom:24px;">
<label style="display:block; font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1.5px; margin-bottom:8px; text-transform:uppercase;">
Nomor Surat
</label>
<input type="text" name="nomor_surat" value="{{ old('nomor_surat') }}"
style="width:100%; padding:14px 16px; background:#f8fafc; border:2px solid transparent; border-radius:12px; font-size:15px; color:#0f172a; outline:none; box-sizing:border-box; transition:all 0.2s; font-family:inherit; font-weight:500;"
onfocus="this.style.borderColor='#e0e7ff'; this.style.background='#fff'" onblur="this.style.borderColor='transparent'; this.style.background='#f8fafc'"
placeholder="Contoh: 001/ST/V/2026" required>
</div>
<div style="margin-bottom:24px;">
<label style="display:block; font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1.5px; margin-bottom:8px; text-transform:uppercase;">
Nama Kegiatan
</label>
<input type="text" name="kegiatan" value="{{ old('kegiatan') }}"
style="width:100%; padding:14px 16px; background:#f8fafc; border:2px solid transparent; border-radius:12px; font-size:15px; color:#0f172a; outline:none; box-sizing:border-box; transition:all 0.2s; font-family:inherit; font-weight:500;"
onfocus="this.style.borderColor='#e0e7ff'; this.style.background='#fff'" onblur="this.style.borderColor='transparent'; this.style.background='#f8fafc'"
placeholder="Contoh: Monitoring Jaringan Dishub" required>
</div>
<div style="margin-bottom:24px;">
<label style="display:block; font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1.5px; margin-bottom:8px; text-transform:uppercase;">
Pilih Petugas (Multiple)
</label>
<select name="pegawai_ids[]" multiple required
style="width:100%; padding:14px 16px; background:#f8fafc; border:2px solid transparent; border-radius:12px; font-size:14px; color:#334155; outline:none; box-sizing:border-box; transition:all 0.2s; font-family:inherit; font-weight:500; height:140px; line-height:1.5;"
onfocus="this.style.borderColor='#e0e7ff'; this.style.background='#fff'" onblur="this.style.borderColor='transparent'; this.style.background='#f8fafc'">
@foreach($users as $user)
<option value="{{ $user['id'] }}" style="padding:6px 0; border-bottom:1px solid #f1f5f9;">
{{ $user['name'] }} - {{ $user['jabatan'] ?? 'Pegawai' }}
</option>
@endforeach
</select>
<p style="font-size:11px; color:#94a3b8; margin-top:8px; font-weight:500;">* Tahan Ctrl/Cmd untuk memilih lebih dari 1 orang</p>
</div>
<div class="date-grid">
<div>
<label style="display:block; font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1.5px; margin-bottom:8px; text-transform:uppercase;">
Tanggal Mulai
</label>
<input type="date" name="tanggal_mulai" value="{{ old('tanggal_mulai') }}"
style="width:100%; padding:14px 16px; background:#f8fafc; border:2px solid transparent; border-radius:12px; font-size:14px; color:#334155; outline:none; box-sizing:border-box; transition:all 0.2s; font-family:inherit; font-weight:500; color-scheme:light;"
onfocus="this.style.borderColor='#e0e7ff'; this.style.background='#fff'" onblur="this.style.borderColor='transparent'; this.style.background='#f8fafc'" required>
</div>
<div>
<label style="display:block; font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1.5px; margin-bottom:8px; text-transform:uppercase;">
Tanggal Selesai
</label>
<input type="date" name="tanggal_selesai" value="{{ old('tanggal_selesai') }}"
style="width:100%; padding:14px 16px; background:#f8fafc; border:2px solid transparent; border-radius:12px; font-size:14px; color:#334155; outline:none; box-sizing:border-box; transition:all 0.2s; font-family:inherit; font-weight:500; color-scheme:light;"
onfocus="this.style.borderColor='#e0e7ff'; this.style.background='#fff'" onblur="this.style.borderColor='transparent'; this.style.background='#f8fafc'">
</div>
</div>
<button type="submit"
style="width:100%; padding:16px; background:#0D215C; color:#fff; border:none; border-radius:12px; font-size:15px; font-weight:800; cursor:pointer; font-family:inherit; transition:all 0.2s;"
onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 8px 20px rgba(13,33,92,0.2)'"
onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'">
Konfirmasi & Kirim Tugas
</button>
</form>
</div>
{{-- KEMBALI LINK --}}
<div style="margin-top:30px;">
<a href="{{ route('admin.superadmin.dashboard') }}"
style="font-size:13px; font-weight:700; color:#64748b; letter-spacing:1px; text-decoration:none; text-transform:uppercase; transition:color 0.2s;"
onmouseover="this.style.color='#0D215C'" onmouseout="this.style.color='#64748b'">
Kembali Ke Dashboard
</a>
</div>
</div>
@endsection
@@ -0,0 +1,202 @@
@extends('admin.layouts.app')
@section('content')
<style>
.page-container { padding: 40px 20px; background: #f4f7fb; min-height: calc(100vh - 70px); font-family: 'Outfit', 'Segoe UI', sans-serif; display: flex; flex-direction: column; align-items: center; box-sizing: border-box; }
.detail-card { background: #fff; border-radius: 24px; box-shadow: 0 10px 40px rgba(0,0,0,0.03); width: 100%; max-width: 700px; overflow: hidden; box-sizing: border-box; }
.card-header { padding: 30px 40px; border-bottom: 1px solid #f1f5f9; display: flex; justify-content: space-between; align-items: flex-start; }
.info-grid { padding: 30px 40px; display: flex; gap: 30px; border-top: 1px solid #f1f5f9; }
.section-padding { padding: 30px 40px; }
.action-card { margin-top: 20px; background: white; padding: 24px 30px; border-radius: 16px; border: 1px solid #e2e8f0; box-shadow: 0 4px 6px rgba(0,0,0,0.02); width: 100%; max-width: 700px; box-sizing: border-box; }
.action-flex { display: flex; gap: 16px; flex-wrap: wrap; }
.revision-form { display: flex; gap: 10px; flex: 1; min-width: 300px; }
@media (max-width: 768px) {
.page-container { padding: 20px 15px !important; }
.detail-card { border-radius: 16px !important; }
.card-header { flex-direction: column !important; gap: 20px !important; padding: 20px 20px !important; }
.card-header > div:last-child { text-align: left !important; }
.info-grid { flex-direction: column !important; gap: 20px !important; padding: 20px 20px !important; }
.section-padding { padding: 20px 20px !important; }
.action-card { padding: 20px !important; }
.revision-form { flex-direction: column !important; min-width: 100% !important; }
.revision-form button { width: 100% !important; }
}
</style>
<div class="page-container">
{{-- HEADER --}}
<div style="text-align:center; margin-bottom:30px;">
<h1 style="font-size:28px; font-weight:800; color:#0f172a; margin:0 0 8px; letter-spacing:-0.5px;">Detail Penugasan</h1>
<p style="margin:0; color:#64748b; font-size:15px; font-weight:500;">Tinjauan lengkap tentang kegiatan dan petugas yang ditugaskan</p>
</div>
@if(session('success'))
<div style="width:100%; max-width:700px; margin-bottom:20px; padding:14px 18px; background:#ecfdf5; border:1px solid #a7f3d0; border-radius:12px; color:#047857; font-size:14px; font-weight:600; display:flex; align-items:center; gap:8px;">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg>
{{ session('success') }}
</div>
@endif
{{-- DETAIL CARD --}}
<div class="detail-card">
<div class="card-header">
<div>
<span style="display:inline-block; padding:6px 12px; border-radius:20px; font-size:11px; font-weight:800; letter-spacing:1px; text-transform:uppercase; margin-bottom:12px;
{{ $activity->status == 'selesai' ? 'background:#ecfdf5; color:#059669;' :
($activity->status == 'dibatalkan' ? 'background:#fef2f2; color:#dc2626;' : 'background:#eff6ff; color:#2563eb;') }}">
{{ str_replace('_', ' ', $activity->status) }}
</span>
<h2 style="margin:0 0 5px; font-size:22px; font-weight:800; color:#0f172a;">{{ $activity->nama_kegiatan }}</h2>
<div style="color:#64748b; font-size:13px; font-weight:500;">Nomor Surat: {{ $activity->nomor_surat ?? '-' }}</div>
</div>
<div style="text-align:right;">
<div style="font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1px; text-transform:uppercase; margin-bottom:4px;">Tanggal Mulai</div>
<div style="font-size:15px; font-weight:700; color:#0f172a; margin-bottom:10px;">{{ \Carbon\Carbon::parse($activity->tanggal)->translatedFormat('d F Y') }}</div>
<div style="font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1px; text-transform:uppercase; margin-bottom:4px;">Tenggat Waktu</div>
<div style="font-size:15px; font-weight:700; color:#0f172a;">
@if($activity->tanggal_selesai)
@php
$isOverdue = \Carbon\Carbon::parse($activity->tanggal_selesai)->isPast() && $activity->status !== 'selesai' && $activity->status !== 'telah_ditinjau';
@endphp
<span style="{{ $isOverdue ? 'color:#dc2626; font-weight:800;' : '' }}">
{{ \Carbon\Carbon::parse($activity->tanggal_selesai)->translatedFormat('d F Y') }}
@if($isOverdue) <span style="font-size:11px; color:#ef4444; margin-left:4px;">(Terlambat)</span> @endif
</span>
@else
-
@endif
</div>
</div>
</div>
<div class="section-padding" style="background:#f8fafc;">
<h3 style="font-size:13px; font-weight:800; color:#64748b; letter-spacing:1.5px; text-transform:uppercase; margin:0 0 16px;">Ditugaskan Kepada</h3>
<div style="display:flex; flex-direction:column; gap:12px;">
@forelse($activity->petugas ?? [] as $petugas)
<div style="display:flex; align-items:center; gap:15px; background:#fff; padding:12px 16px; border-radius:12px; border:1px solid #e2e8f0;">
<div style="width:40px; height:40px; border-radius:50%; background:#e0e7ff; color:#3730a3; display:flex; align-items:center; justify-content:center; font-weight:800; font-size:14px;">
{{ strtoupper(substr($petugas['name'], 0, 2)) }}
</div>
<div>
<div style="font-size:14px; font-weight:700; color:#0f172a; margin-bottom:2px;">{{ $petugas['name'] }}</div>
<div style="font-size:12px; color:#64748b; font-weight:500;">{{ $petugas['jabatan'] ?? 'Petugas Lapangan' }}</div>
</div>
</div>
@empty
<div style="font-size:13px; color:#94a3b8; font-style:italic;">Belum ada petugas yang ditetapkan.</div>
@endforelse
</div>
</div>
<div class="info-grid">
<div style="flex:1;">
<div style="font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1px; text-transform:uppercase; margin-bottom:6px;">Lokasi Tugas</div>
<div style="font-size:14px; font-weight:600; color:#0f172a;">{{ $activity->lokasi ?? '-' }}</div>
</div>
<div style="flex:1;">
<div style="font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1px; text-transform:uppercase; margin-bottom:6px;">Deskripsi Tugas</div>
<div style="font-size:14px; font-weight:500; color:#334155;">{{ $activity->deskripsi ?? '-' }}</div>
</div>
</div>
@if(!empty($activity->status_note))
<div class="section-padding" style="background:#eff6ff; border-top:1px solid #bfdbfe;">
<div style="font-size:11px; font-weight:800; color:#2563eb; letter-spacing:1px; text-transform:uppercase; margin-bottom:8px;">Catatan Status Terakhir</div>
<div style="font-size:14px; font-weight:500; color:#1e3a8a; line-height:1.6;">{{ $activity->status_note }}</div>
</div>
@endif
{{-- TIMELINE PROGRESS MONITORING --}}
<div class="section-padding" style="background:#ffffff; border-top:1px solid #f1f5f9;">
<div style="font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1px; text-transform:uppercase; margin-bottom:20px;">Log Monitoring Progress</div>
@if(isset($activity->progress) && count($activity->progress) > 0)
<div style="position:relative; border-left:2px solid #e0e7ff; margin-left:10px; padding-left:20px; display:flex; flex-direction:column; gap:24px;">
@foreach($activity->progress as $prog)
<div style="position:relative;">
<div style="position:absolute; left:-27px; top:4px; width:12px; height:12px; background:#6366f1; border-radius:50%; border:2px solid #fff;"></div>
<div style="font-size:12px; color:#64748b; margin-bottom:4px;">
{{ \Carbon\Carbon::parse($prog['created_at'])->format('d M Y, H:i') }}
<span style="font-weight:700; color:#6366f1;">{{ $prog['user']['name'] ?? 'Pegawai' }}</span>
</div>
<div style="font-size:14px; color:#334155; background:#f8fafc; border:1px solid #f1f5f9; padding:12px 16px; border-radius:10px;">
{{ $prog['note'] }}
@if(!empty($prog['attachment']))
<div style="margin-top:10px; padding-top:10px; border-top:1px solid #e2e8f0;">
<a href="http://127.0.0.1:8000/{{ $prog['attachment'] }}" target="_blank"
style="display:inline-block; font-size:12px; font-weight:600; color:#4f46e5; text-decoration:none; background:#e0e7ff; padding:4px 10px; border-radius:6px; border:1px solid #c7d2fe;">
📎 Lihat Lampiran Bukti
</a>
</div>
@endif
</div>
</div>
@endforeach
</div>
@else
<div style="font-size:13px; color:#64748b; background:#f8fafc; padding:20px; border-radius:10px; text-align:center; border:1px dashed #cbd5e1;">
Belum ada log progress yang dicatat untuk kegiatan ini.
</div>
@endif
</div>
<div class="info-grid">
<div style="flex:1;">
<div style="font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1px; text-transform:uppercase; margin-bottom:6px;">Dibuat Oleh</div>
<div style="font-size:14px; font-weight:600; color:#0f172a;">{{ $activity->user->name ?? 'System' }}</div>
</div>
<div style="flex:1;">
<div style="font-size:11px; font-weight:800; color:#94a3b8; letter-spacing:1px; text-transform:uppercase; margin-bottom:6px;">Pembaruan Terakhir</div>
<div style="font-size:14px; font-weight:600; color:#0f172a;">{{ $activity->updated_at->diffForHumans() }}</div>
</div>
</div>
</div>
{{-- TINDAKAN REVIEW (SUPERADMIN) --}}
@if($activity->status == 'selesai')
<div class="action-card">
<h4 style="margin-top:0; margin-bottom:16px; font-size:16px; color:#1e293b;">Tindakan Review (Verifikasi)</h4>
<div class="action-flex">
{{-- Setujui (Telah Ditinjau) --}}
<form action="{{ route('admin.superadmin.kegiatan.approve', $activity->id) }}" method="POST">
@csrf
<button type="submit" onclick="return confirm('Setujui laporan ini?')"
style="background:#16a34a; color:white; border:none; padding:10px 20px; border-radius:10px; font-weight:600; font-size:14px; cursor:pointer; transition:0.2s;"
onmouseover="this.style.background='#15803d'" onmouseout="this.style.background='#16a34a'">
Setujui (Telah Ditinjau)
</button>
</form>
{{-- Minta Revisi --}}
<form action="{{ route('admin.superadmin.kegiatan.revision', $activity->id) }}" method="POST" class="revision-form">
@csrf
<input type="text" name="status_note" required placeholder="Catatan Revisi (misal: Mohon perbaiki foto)"
style="flex:1; padding:10px 16px; border:1px solid #cbd5e1; border-radius:10px; font-size:14px; outline:none;"
onfocus="this.style.borderColor='#3b82f6'" onblur="this.style.borderColor='#cbd5e1'">
<button type="submit" onclick="return confirm('Kembalikan laporan ini ke pegawai untuk direvisi?')"
style="background:#f59e0b; color:white; border:none; padding:10px 20px; border-radius:10px; font-weight:600; font-size:14px; cursor:pointer; transition:0.2s; white-space:nowrap;"
onmouseover="this.style.background='#d97706'" onmouseout="this.style.background='#f59e0b'">
Minta Revisi
</button>
</form>
</div>
</div>
@endif
{{-- KEMBALI LINK --}}
<div style="margin-top:30px;">
<a href="{{ route('admin.superadmin.dashboard') }}"
style="font-size:13px; font-weight:700; color:#64748b; letter-spacing:1px; text-decoration:none; text-transform:uppercase; transition:color 0.2s;"
onmouseover="this.style.color='#0D215C'" onmouseout="this.style.color='#64748b'">
Kembali Ke Dashboard
</a>
</div>
</div>
@endsection
@@ -0,0 +1,222 @@
@extends('admin.layouts.app')
@section('content')
<style>
.page-container { padding: 28px 32px; background: #f1f5f9; min-height: 100vh; font-family: 'Figtree', 'Segoe UI', sans-serif; }
.header-flex { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 28px; }
.main-grid { display: grid; grid-template-columns: 1fr 300px; gap: 20px; align-items: flex-start; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
.form-actions { border-top: 1px solid #f1f5f9; padding-top: 20px; display: flex; gap: 10px; justify-content: flex-end; }
@media (max-width: 768px) {
.page-container { padding: 16px 12px !important; }
.header-flex { flex-direction: column !important; gap: 16px !important; }
.main-grid { grid-template-columns: 1fr !important; }
.form-grid { grid-template-columns: 1fr !important; gap: 15px !important; }
.form-actions { flex-direction: column !important; }
.form-actions a, .form-actions button { width: 100% !important; justify-content: center; }
}
</style>
<div class="page-container">
{{-- HEADER --}}
<div class="header-flex">
<div>
<a href="{{ route('admin.superadmin.user.index') }}"
style="font-size:12px; color:#64748b; text-decoration:none; display:inline-flex; align-items:center; gap:5px; margin-bottom:10px; font-weight:600;"
onmouseover="this.style.color='#0D215C'" onmouseout="this.style.color='#64748b'">
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path d="M19 12H5M12 5l-7 7 7 7"/>
</svg>
Kembali ke Manajemen Pengguna
</a>
<p style="font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:1.8px; margin:0 0 6px; text-transform:uppercase;">Panel Kendali Sistem</p>
<h1 style="font-size:28px; font-weight:800; color:#0f172a; margin:0 0 4px;">Tambah Pengguna</h1>
<p style="margin:0; color:#94a3b8; font-size:13px;">Buat akun baru untuk pegawai atau administrator sistem</p>
</div>
<div style="background:#eef2ff; color:#4338ca; padding:9px 14px; border-radius:10px; font-size:12px; font-weight:700; display:flex; align-items:center; gap:6px;">
<div style="width:8px; height:8px; background:#4338ca; border-radius:50%;"></div>
{{ strtoupper(session('user')['role'] ?? 'ADMINISTRATOR') }}
</div>
</div>
@if(session('error'))
<div style="margin-bottom:20px; padding:14px 18px; background:#fff1f2; border:1px solid #fecdd3; border-radius:12px; color:#be123c; font-size:14px; font-weight:600; display:flex; align-items:center; gap:8px;">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><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"/></svg>
{{ session('error') }}
</div>
@endif
<div class="main-grid">
{{-- FORM CARD --}}
<div style="background:#fff; border-radius:16px; border:1px solid #e2e8f0; overflow:hidden;">
<div style="padding:20px 24px; border-bottom:1px solid #f1f5f9; display:flex; align-items:center; gap:10px;">
<div style="width:32px; height:32px; background:#eff6ff; border-radius:8px; display:flex; align-items:center; justify-content:center;">
<svg width="16" height="16" fill="none" stroke="#2563eb" stroke-width="2" viewBox="0 0 24 24">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<line x1="19" y1="8" x2="19" y2="14"/>
<line x1="22" y1="11" x2="16" y2="11"/>
</svg>
</div>
<h3 style="margin:0; font-size:16px; font-weight:700; color:#0f172a;">Data Pengguna Baru</h3>
</div>
<form action="{{ route('admin.superadmin.user.store') }}" method="POST" style="padding:28px 24px;">
@csrf
@if ($errors->any())
<div style="margin-bottom:20px; padding:14px 18px; background:#fff1f2; border:1px solid #fecdd3; border-radius:12px;">
<p style="font-weight:700; color:#be123c; margin:0 0 8px; font-size:13px;">Terdapat kesalahan input:</p>
<ul style="margin:0; padding-left:18px; color:#be123c; font-size:13px;">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="form-grid">
{{-- NAMA --}}
<div>
<label style="display:block; font-size:13px; font-weight:700; color:#374151; margin-bottom:8px;">
Nama Lengkap <span style="color:#ef4444;">*</span>
</label>
<input type="text" name="name" value="{{ old('name') }}"
style="width:100%; padding:11px 14px; border:1.5px solid #e2e8f0; border-radius:10px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box;"
onfocus="this.style.borderColor='#2563eb'" onblur="this.style.borderColor='#e2e8f0'"
placeholder="Nama lengkap pegawai" required>
</div>
{{-- USERNAME --}}
<div>
<label style="display:block; font-size:13px; font-weight:700; color:#374151; margin-bottom:8px;">
Username <span style="color:#ef4444;">*</span>
</label>
<input type="text" name="username" value="{{ old('username') }}"
style="width:100%; padding:11px 14px; border:1.5px solid #e2e8f0; border-radius:10px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box;"
onfocus="this.style.borderColor='#2563eb'" onblur="this.style.borderColor='#e2e8f0'"
placeholder="Username untuk login" required>
</div>
</div>
<div class="form-grid">
{{-- PASSWORD --}}
<div>
<label style="display:block; font-size:13px; font-weight:700; color:#374151; margin-bottom:8px;">
Kata Sandi <span style="color:#ef4444;">*</span>
</label>
<div style="position:relative;">
<input type="password" name="password" id="password_field"
style="width:100%; padding:11px 40px 11px 14px; border:1.5px solid #e2e8f0; border-radius:10px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box;"
onfocus="this.style.borderColor='#2563eb'" onblur="this.style.borderColor='#e2e8f0'"
placeholder="Minimal 6 karakter" required>
<button type="button" onclick="togglePassword('password_field', this)"
style="position:absolute; right:12px; top:50%; transform:translateY(-50%); background:none; border:none; cursor:pointer; color:#94a3b8; padding:0; display:flex; align-items:center; justify-content:center;">
<svg class="eye-icon" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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"/>
</svg>
<svg class="eye-off-icon" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" style="display:none;">
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
<line x1="1" y1="1" x2="23" y2="23"/>
</svg>
</button>
</div>
</div>
{{-- ROLE --}}
<div>
<label style="display:block; font-size:13px; font-weight:700; color:#374151; margin-bottom:8px;">
Hak Akses (Role) <span style="color:#ef4444;">*</span>
</label>
<select name="role"
style="width:100%; padding:11px 14px; border:1.5px solid #e2e8f0; border-radius:10px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box; background:#fff;"
onfocus="this.style.borderColor='#2563eb'" onblur="this.style.borderColor='#e2e8f0'">
<option value="user" {{ old('role') == 'user' ? 'selected' : '' }}>Petugas (User)</option>
<option value="admin" {{ old('role') == 'admin' ? 'selected' : '' }}>Admin (KASI)</option>
<option value="superadmin" {{ old('role') == 'superadmin' ? 'selected' : '' }}>Super Admin</option>
</select>
</div>
</div>
<div class="form-actions">
<a href="{{ route('admin.superadmin.user.index') }}"
style="padding:10px 20px; border:1.5px solid #e2e8f0; border-radius:10px; font-size:13px; font-weight:700; color:#64748b; text-decoration:none; background:#f8fafc;"
onmouseover="this.style.background='#e2e8f0'" onmouseout="this.style.background='#f8fafc'">
Batal
</a>
<button type="submit"
style="padding:10px 24px; background:#0D215C; color:#fff; border:none; border-radius:10px; font-size:13px; font-weight:700; cursor:pointer; display:flex; align-items:center; gap:7px;"
onmouseover="this.style.opacity='.85'" onmouseout="this.style.opacity='1'">
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<line x1="19" y1="8" x2="19" y2="14"/>
<line x1="22" y1="11" x2="16" y2="11"/>
</svg>
Tambah Pengguna
</button>
</div>
</form>
</div>
{{-- TIPS CARD --}}
<div>
<div style="background:#fff; border-radius:16px; border:1px solid #e2e8f0; padding:20px; margin-bottom:16px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:12px;">
<div style="width:28px; height:28px; background:#f0fdf4; border-radius:8px; display:flex; align-items:center; justify-content:center;">
<svg width="14" height="14" fill="none" stroke="#10b981" stroke-width="2" viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12"/>
</svg>
</div>
<span style="font-size:14px; font-weight:700; color:#0f172a;">Panduan Pengisian</span>
</div>
<ul style="margin:0; padding-left:16px; font-size:12px; color:#64748b; line-height:1.9;">
<li>Nama sesuai dengan dokumen resmi</li>
<li>Username digunakan untuk login</li>
<li>Kata sandi minimal 6 karakter</li>
</ul>
</div>
<div style="background:#eff6ff; border-radius:16px; border:1px solid #bfdbfe; padding:18px 20px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:10px;">
<svg width="16" height="16" fill="#2563eb" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
<span style="font-size:13px; font-weight:700; color:#1d4ed8;">Panduan Role</span>
</div>
<ul style="margin:0; padding-left:16px; font-size:12px; color:#3b82f6; line-height:1.8;">
<li><strong>Petugas</strong>: Input kegiatan harian</li>
<li><strong>Admin</strong>: Monitor kegiatan & user</li>
<li><strong>Super Admin</strong>: Akses penuh sistem</li>
</ul>
</div>
</div>
</div>
</div>
@endsection
<script>
function togglePassword(inputId, buttonElement) {
const input = document.getElementById(inputId);
const eyeIcon = buttonElement.querySelector('.eye-icon');
const eyeOffIcon = buttonElement.querySelector('.eye-off-icon');
if (input.type === 'password') {
input.type = 'text';
eyeIcon.style.display = 'none';
eyeOffIcon.style.display = 'block';
buttonElement.style.color = '#2563eb';
} else {
input.type = 'password';
eyeIcon.style.display = 'block';
eyeOffIcon.style.display = 'none';
buttonElement.style.color = '#94a3b8';
}
}
</script>
@@ -0,0 +1,346 @@
@extends('admin.layouts.app')
@section('content')
<style>
.page-container { padding: 28px 32px; background: #f1f5f9; min-height: 100vh; font-family: 'Figtree', 'Segoe UI', sans-serif; }
.header-flex { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 28px; }
.main-grid { display: grid; grid-template-columns: 1fr 300px; gap: 24px; align-items: flex-start; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.form-actions { border-top: 1px solid #f1f5f9; padding-top: 24px; display: flex; justify-content: space-between; align-items: center; }
@media (max-width: 768px) {
.page-container { padding: 16px 12px !important; }
.header-flex { flex-direction: column !important; gap: 16px !important; align-items: flex-start !important; }
.main-grid { grid-template-columns: 1fr !important; }
.form-grid { grid-template-columns: 1fr !important; gap: 15px !important; }
.form-actions { flex-direction: column !important; gap: 16px !important; align-items: flex-start !important; }
.form-actions a, .form-actions button { width: 100% !important; justify-content: center; }
}
</style>
<div class="page-container">
{{-- HEADER --}}
<div class="header-flex">
<div>
<div style="display:flex; align-items:center; gap:8px; margin-bottom:8px;">
<div style="width:24px; height:2px; background:#3b82f6;"></div>
<p style="font-size:11px; font-weight:700; color:#3b82f6; letter-spacing:1px; margin:0; text-transform:uppercase;">
Panel Kendali Sistem
</p>
</div>
<h1 style="font-size:28px; font-weight:800; color:#0f172a; margin:0 0 4px;">
Edit Pengguna
</h1>
<p style="margin:0; color:#64748b; font-size:13px;">
Ubah informasi akun dan hak akses pengguna
</p>
</div>
<div style="display:flex; align-items:center; gap:12px;">
<a href="{{ route('admin.superadmin.user.index') }}"
style="background:#fff; border:1px solid #e2e8f0; padding:8px 16px; border-radius:999px; font-size:12px; font-weight:600; color:#475569; text-decoration:none; display:flex; align-items:center; gap:6px;">
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M19 12H5M12 5l-7 7 7 7"/>
</svg>
Kembali ke Daftar
</a>
<div style="background:#fef3c7; color:#b45309; border:1px solid #fde68a; padding:8px 16px; border-radius:999px; font-size:11px; font-weight:800; display:flex; align-items:center; gap:6px; letter-spacing:0.5px;">
<svg width="12" height="12" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
</svg>
SUPER ADMIN
</div>
</div>
</div>
@if(session('success'))
<div style="margin-bottom:20px; padding:14px 18px; background:#f0fdf4; border:1px solid #bbf7d0; border-radius:12px; color:#15803d; font-size:14px; font-weight:600; display:flex; align-items:center; gap:8px;">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div style="margin-bottom:20px; padding:14px 18px; background:#fff1f2; border:1px solid #fecdd3; border-radius:12px; color:#be123c; font-size:14px; font-weight:600; display:flex; align-items:center; gap:8px;">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><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"/></svg>
{{ session('error') }}
</div>
@endif
@if ($errors->any())
<div style="margin-bottom:20px; padding:14px 18px; background:#fff1f2; border:1px solid #fecdd3; border-radius:12px;">
<p style="font-weight:700; color:#be123c; margin:0 0 8px; font-size:13px;">Terdapat kesalahan input:</p>
<ul style="margin:0; padding-left:18px; color:#be123c; font-size:13px;">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="main-grid">
{{-- LEFT SIDEBAR --}}
<div>
{{-- Profile Card --}}
<div style="background:#fff; border-radius:16px; border:1px solid #e2e8f0; overflow:hidden; margin-bottom:16px; box-shadow:0 4px 6px -1px rgba(0,0,0,0.05);">
{{-- Gradient Top --}}
<div style="background: linear-gradient(135deg, #2563eb 0%, #6366f1 100%); padding:32px 20px; text-align:center; position:relative;">
@php
$initials = strtoupper(substr($user->name, 0, 2));
@endphp
<div style="width:72px; height:72px; background:rgba(255,255,255,0.2); border:2px solid rgba(255,255,255,0.4); border-radius:20px; color:#fff; display:flex; align-items:center; justify-content:center; font-weight:800; font-size:24px; margin:0 auto 16px; box-shadow:0 4px 12px rgba(0,0,0,0.1); backdrop-filter:blur(4px);">
{{ $initials }}
</div>
<h2 style="margin:0 0 4px; color:#fff; font-size:18px; font-weight:700;">{{ $user->name }}</h2>
<p style="margin:0 0 16px; color:#e0e7ff; font-size:12px;">{{ $user->email ?? $user->username }}</p>
<div style="display:inline-flex; align-items:center; gap:6px; background:rgba(255,255,255,0.2); padding:6px 14px; border-radius:999px; border:1px solid rgba(255,255,255,0.3); color:#fff; font-size:10px; font-weight:800; letter-spacing:0.5px;">
<svg width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
{{ strtoupper($user->role) }}
</div>
</div>
{{-- Stats List --}}
<div style="padding:16px;">
<div style="display:flex; align-items:center; gap:12px; padding:12px; background:#f8fafc; border-radius:12px; border:1px solid #f1f5f9; margin-bottom:12px;">
<div style="color:#64748b;"><svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2" ry="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"/></svg></div>
<div>
<div style="font-size:10px; font-weight:700; color:#94a3b8; text-transform:uppercase; letter-spacing:0.5px; margin-bottom:2px;">User ID</div>
<div style="font-size:13px; font-weight:700; color:#0f172a;">#{{ $user->id }}</div>
</div>
</div>
<div style="display:flex; align-items:center; gap:12px; padding:12px; background:#f8fafc; border-radius:12px; border:1px solid #f1f5f9; margin-bottom:12px;">
<div style="color:#10b981;"><svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg></div>
<div>
<div style="font-size:10px; font-weight:700; color:#94a3b8; text-transform:uppercase; letter-spacing:0.5px; margin-bottom:2px;">Total Aktivitas</div>
<div style="font-size:13px; font-weight:700; color:#0f172a;">{{ $user->activities_count ?? 0 }} kegiatan</div>
</div>
</div>
<div style="display:flex; align-items:center; gap:12px; padding:12px; background:#f8fafc; border-radius:12px; border:1px solid #f1f5f9; margin-bottom:12px;">
<div style="color:#8b5cf6;"><svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2" ry="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"/></svg></div>
<div>
<div style="font-size:10px; font-weight:700; color:#94a3b8; text-transform:uppercase; letter-spacing:0.5px; margin-bottom:2px;">Bergabung</div>
<div style="font-size:13px; font-weight:700; color:#0f172a;">{{ \Carbon\Carbon::parse($user->created_at)->translatedFormat('d F Y') }}</div>
</div>
</div>
<div style="display:flex; align-items:center; gap:12px; padding:12px; background:#f8fafc; border-radius:12px; border:1px solid #f1f5f9;">
<div style="color:#f59e0b;"><svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2" ry="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"/></svg></div>
<div>
<div style="font-size:10px; font-weight:700; color:#94a3b8; text-transform:uppercase; letter-spacing:0.5px; margin-bottom:2px;">Terakhir Diperbarui</div>
<div style="font-size:13px; font-weight:700; color:#0f172a;">{{ \Carbon\Carbon::parse($user->updated_at ?? $user->created_at)->translatedFormat('d F Y') }}</div>
</div>
</div>
</div>
{{-- Warning Box --}}
<div style="margin:0 16px 16px; padding:14px; background:#fefce8; border:1px solid #fef08a; border-radius:12px; display:flex; gap:10px; align-items:flex-start;">
<div style="color:#b45309; flex-shrink:0;">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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"/>
</svg>
</div>
<div style="font-size:11px; color:#b45309; line-height:1.5;">
Perubahan data akan langsung berpengaruh pada akses sistem pengguna ini.
</div>
</div>
</div>
</div>
{{-- FORM MAIN CONTENT --}}
<div style="background:#fff; border-radius:16px; border:1px solid #e2e8f0; overflow:hidden; box-shadow:0 4px 6px -1px rgba(0,0,0,0.05);">
<div style="padding:20px 28px; border-bottom:1px solid #f1f5f9; display:flex; align-items:center; gap:12px;">
<div style="width:36px; height:36px; background:#eff6ff; border-radius:10px; display:flex; align-items:center; justify-content:center; color:#3b82f6;">
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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"/>
</svg>
</div>
<div>
<h3 style="margin:0 0 4px; font-size:15px; font-weight:700; color:#0f172a;">Formulir Edit Pengguna</h3>
<p style="margin:0; font-size:12px; color:#94a3b8;">Perbarui informasi akun pengguna di bawah ini</p>
</div>
</div>
<form action="{{ route('admin.superadmin.user.update', $user->id) }}" method="POST" style="padding:28px;">
@csrf
{{-- INFORMASI DASAR --}}
<div style="margin-bottom:28px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:16px;">
<div style="width:6px; height:6px; background:#3b82f6; border-radius:50%;"></div>
<h4 style="margin:0; font-size:12px; font-weight:800; color:#3b82f6; letter-spacing:1px;">INFORMASI DASAR</h4>
</div>
<div class="form-grid">
<div>
<label style="display:block; font-size:12px; font-weight:600; color:#475569; margin-bottom:8px;">
Nama Lengkap <span style="color:#ef4444;">*</span>
</label>
<input type="text" name="name" value="{{ old('name', $user->name) }}"
style="width:100%; padding:10px 14px; border:1px solid #e2e8f0; border-radius:8px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box; background:#f8fafc;"
onfocus="this.style.borderColor='#3b82f6'; this.style.background='#fff'"
onblur="this.style.borderColor='#e2e8f0'; this.style.background='#f8fafc'" required>
</div>
<div>
<label style="display:block; font-size:12px; font-weight:600; color:#475569; margin-bottom:8px;">
Username <span style="color:#ef4444;">*</span>
</label>
<input type="text" name="username" value="{{ old('username', $user->username) }}"
style="width:100%; padding:10px 14px; border:1px solid #e2e8f0; border-radius:8px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box; background:#f8fafc;"
onfocus="this.style.borderColor='#3b82f6'; this.style.background='#fff'"
onblur="this.style.borderColor='#e2e8f0'; this.style.background='#f8fafc'" required>
</div>
</div>
</div>
{{-- ROLE & HAK AKSES --}}
<div style="margin-bottom:28px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:16px;">
<div style="width:6px; height:6px; background:#3b82f6; border-radius:50%;"></div>
<h4 style="margin:0; font-size:12px; font-weight:800; color:#3b82f6; letter-spacing:1px;">ROLE & HAK AKSES</h4>
</div>
<div>
<label style="display:block; font-size:12px; font-weight:600; color:#475569; margin-bottom:8px;">
Role Pengguna <span style="color:#ef4444;">*</span>
</label>
<select name="role"
style="width:100%; padding:10px 14px; border:1px solid #e2e8f0; border-radius:8px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box; background:#f8fafc; appearance:none;"
onfocus="this.style.borderColor='#3b82f6'; this.style.background='#fff'"
onblur="this.style.borderColor='#e2e8f0'; this.style.background='#f8fafc'" required>
<option value="superadmin" {{ old('role', $user->role) == 'superadmin' ? 'selected' : '' }}>Super Admin</option>
<option value="admin" {{ old('role', $user->role) == 'admin' ? 'selected' : '' }}>Administrator</option>
<option value="user" {{ old('role', $user->role) == 'user' ? 'selected' : '' }}>User</option>
</select>
<p style="margin:6px 0 0; font-size:11px; color:#94a3b8; display:flex; align-items:center; gap:4px;">
<svg width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
Role menentukan level akses pengguna di dalam sistem
</p>
</div>
</div>
{{-- GANTI PASSWORD --}}
<div style="margin-bottom:32px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:16px;">
<div style="width:6px; height:6px; background:#3b82f6; border-radius:50%;"></div>
<h4 style="margin:0; font-size:12px; font-weight:800; color:#3b82f6; letter-spacing:1px;">GANTI PASSWORD <span style="font-weight:500; color:#94a3b8; text-transform:none; letter-spacing:0;">(Kosongkan jika tidak ingin mengubah)</span></h4>
</div>
<div class="form-grid">
<div>
<div style="display:flex; align-items:center; gap:6px; margin-bottom:8px;">
<label style="font-size:12px; font-weight:600; color:#475569;">
Password Baru
</label>
<span style="background:#f1f5f9; color:#64748b; padding:2px 6px; border-radius:4px; font-size:10px;">Opsional</span>
</div>
<div style="position:relative;">
<input type="password" name="password" id="edit_password"
style="width:100%; padding:10px 40px 10px 14px; border:1px solid #e2e8f0; border-radius:8px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box; background:#f8fafc;"
onfocus="this.style.borderColor='#3b82f6'; this.style.background='#fff'"
onblur="this.style.borderColor='#e2e8f0'; this.style.background='#f8fafc'"
placeholder="Min. 8 karakter">
<button type="button" onclick="togglePassword('edit_password', this)"
style="position:absolute; right:12px; top:50%; transform:translateY(-50%); background:none; border:none; cursor:pointer; color:#94a3b8; padding:0; display:flex; align-items:center; justify-content:center;">
<svg class="eye-icon" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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"/>
</svg>
<svg class="eye-off-icon" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" style="display:none;">
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
<line x1="1" y1="1" x2="23" y2="23"/>
</svg>
</button>
</div>
</div>
<div>
<div style="display:flex; align-items:center; gap:6px; margin-bottom:8px;">
<label style="font-size:12px; font-weight:600; color:#475569;">
Konfirmasi Password
</label>
<span style="background:#f1f5f9; color:#64748b; padding:2px 6px; border-radius:4px; font-size:10px;">Opsional</span>
</div>
<div style="position:relative;">
<input type="password" name="password_confirmation" id="edit_password_confirmation"
style="width:100%; padding:10px 40px 10px 14px; border:1px solid #e2e8f0; border-radius:8px; font-size:14px; color:#0f172a; outline:none; box-sizing:border-box; background:#f8fafc;"
onfocus="this.style.borderColor='#3b82f6'; this.style.background='#fff'"
onblur="this.style.borderColor='#e2e8f0'; this.style.background='#f8fafc'"
placeholder="Ulangi password baru">
<button type="button" onclick="togglePassword('edit_password_confirmation', this)"
style="position:absolute; right:12px; top:50%; transform:translateY(-50%); background:none; border:none; cursor:pointer; color:#94a3b8; padding:0; display:flex; align-items:center; justify-content:center;">
<svg class="eye-icon" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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"/>
</svg>
<svg class="eye-off-icon" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" style="display:none;">
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
<line x1="1" y1="1" x2="23" y2="23"/>
</svg>
</button>
</div>
</div>
</div>
</div>
{{-- FOOTER BUTTONS --}}
<div class="form-actions">
<div style="font-size:12px; color:#64748b; display:flex; align-items:center; gap:6px;">
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
Field bertanda <span style="color:#ef4444;">*</span> wajib diisi
</div>
<div style="display:flex; gap:12px;">
<a href="{{ route('admin.superadmin.user.index') }}"
style="padding:10px 24px; border:1px solid #e2e8f0; border-radius:8px; font-size:13px; font-weight:700; color:#475569; text-decoration:none; background:#fff; transition:all .2s;"
onmouseover="this.style.background='#f8fafc'" onmouseout="this.style.background='#fff'">
Batal
</a>
<button type="submit"
style="padding:10px 24px; background:#2563eb; color:#fff; border:none; border-radius:8px; font-size:13px; font-weight:700; cursor:pointer; display:flex; align-items:center; gap:8px; transition:opacity .2s;"
onmouseover="this.style.opacity='.85'" onmouseout="this.style.opacity='1'">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
<polyline points="17 21 17 13 7 13 7 21"/>
<polyline points="7 3 7 8 15 8"/>
</svg>
Simpan Perubahan
</button>
</div>
</div>
</form>
</div>
</div>
</div>
@endsection
<script>
function togglePassword(inputId, buttonElement) {
const input = document.getElementById(inputId);
const eyeIcon = buttonElement.querySelector('.eye-icon');
const eyeOffIcon = buttonElement.querySelector('.eye-off-icon');
if (input.type === 'password') {
input.type = 'text';
eyeIcon.style.display = 'none';
eyeOffIcon.style.display = 'block';
buttonElement.style.color = '#3b82f6';
} else {
input.type = 'password';
eyeIcon.style.display = 'block';
eyeOffIcon.style.display = 'none';
buttonElement.style.color = '#94a3b8';
}
}
</script>
@@ -0,0 +1,328 @@
@extends('admin.layouts.app')
@section('content')
<div class="page-container" style="padding:28px 32px; background:#f1f5f9; min-height:100vh; font-family:'Figtree','Segoe UI',sans-serif;">
<style>
.hover-card {
transition: all .3s ease;
cursor: pointer;
}
.hover-card:hover {
transform: translateY(-8px);
box-shadow: 0 18px 35px rgba(15, 23, 42, .12);
}
@media (max-width: 768px) {
.page-container { padding: 16px 12px !important; }
.header-flex { flex-direction: column !important; gap: 16px !important; }
.stats-grid { grid-template-columns: 1fr !important; }
.toolbar-flex { flex-direction: column !important; align-items: stretch !important; gap: 16px !important; }
.toolbar-right { flex-direction: column !important; align-items: stretch !important; }
.search-input { width: 100% !important; }
.btn-tambah { justify-content: center !important; }
.header-badges { flex-wrap: wrap; }
.table-wrap table { min-width: 800px !important; }
}
</style>
{{-- HEADER --}}
<div class="header-flex" style="display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:24px;">
<div>
<p style="font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:1.8px; margin:0 0 6px; text-transform:uppercase;">
Panel Kendali Sistem
</p>
<h1 style="font-size:30px; font-weight:800; color:#0f172a; margin:0 0 4px;">
Manajemen Pengguna
</h1>
<p style="margin:0; color:#94a3b8; font-size:13px;">
Kelola seluruh akun dan hak akses pengguna sistem
</p>
</div>
<div class="header-badges" style="display:flex; align-items:center; gap:10px;">
<div style="background:#fff; border:1px solid #e2e8f0; padding:9px 14px; border-radius:10px; font-size:13px; color:#64748b; display:flex; align-items:center; gap:6px;">
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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" />
</svg>
{{ now()->translatedFormat('l, d F Y') }}
</div>
<div style="background:#eef2ff; color:#4338ca; padding:9px 14px; border-radius:10px; font-size:12px; font-weight:700; display:flex; align-items:center; gap:6px;">
<div style="width:8px; height:8px; background:#4338ca; border-radius:50%;"></div>
{{ strtoupper(session('user')['role'] ?? 'ADMINISTRATOR') }}
</div>
</div>
</div>
{{-- STATISTIC CARDS --}}
<div class="stats-grid" style="display:grid; grid-template-columns:repeat(3,1fr); gap:16px; margin-bottom:24px;">
{{-- Card 1 --}}
<a href="{{ route('admin.superadmin.user.index') }}"
class="hover-card"
style="text-decoration:none; display:block; background:#fff; border-radius:16px; padding:22px 24px; border:1px solid #e2e8f0; position:relative; overflow:hidden;">
<div style="position:absolute; top:0; left:0; right:0; height:3px; background:#3b82f6;"></div>
<div style="display:flex; justify-content:space-between; align-items:flex-start;">
<div>
<p style="font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:1.2px; margin:0 0 10px; text-transform:uppercase;">
Total Pengguna
</p>
<h2 style="font-size:36px; font-weight:800; margin:0 0 4px; color:#0f172a;">
{{ $stats['total'] }}
</h2>
<p style="font-size:12px; color:#94a3b8; margin:0;">Seluruh akun terdaftar</p>
</div>
<div style="width:44px; height:44px; background:#eff6ff; border-radius:12px; display:flex; align-items:center; justify-content:center;">
<svg width="20" height="20" fill="none" stroke="#3b82f6" stroke-width="2" viewBox="0 0 24 24">
<circle cx="12" cy="8" r="4" />
<path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" />
</svg>
</div>
</div>
</a>
{{-- Card 2 --}}
<a href="{{ route('admin.superadmin.user.index') }}"
class="hover-card"
style="text-decoration:none; display:block; background:#fff; border-radius:16px; padding:22px 24px; border:1px solid #e2e8f0; position:relative; overflow:hidden;">
<div style="position:absolute; top:0; left:0; right:0; height:3px; background:#10b981;"></div>
<div style="display:flex; justify-content:space-between; align-items:flex-start;">
<div>
<p style="font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:1.2px; margin:0 0 10px; text-transform:uppercase;">
Pengguna Aktif
</p>
<h2 style="font-size:36px; font-weight:800; margin:0 0 4px; color:#0f172a;">
{{ $stats['active'] }}
</h2>
<p style="font-size:12px; color:#94a3b8; margin:0;">Memiliki aktivitas tercatat</p>
</div>
<div style="width:44px; height:44px; background:#f0fdf4; border-radius:12px; display:flex; align-items:center; justify-content:center;">
<svg width="20" height="20" fill="none" stroke="#10b981" stroke-width="2" viewBox="0 0 24 24">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
</div>
</div>
</a>
{{-- Card 3 --}}
<div class="hover-card" style="background:#fff; border-radius:16px; padding:22px 24px; border:1px solid #e2e8f0; position:relative; overflow:hidden;">
<div style="position:absolute; top:0; left:0; right:0; height:3px; background:#8b5cf6;"></div>
<div style="display:flex; justify-content:space-between; align-items:flex-start;">
<div>
<p style="font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:1.2px; margin:0 0 10px; text-transform:uppercase;">
Total Aktivitas
</p>
<h2 style="font-size:36px; font-weight:800; margin:0 0 4px; color:#0f172a;">
{{ $stats['activities'] }}
</h2>
<p style="font-size:12px; color:#94a3b8; margin:0;">Dari seluruh pengguna</p>
</div>
<div style="width:44px; height:44px; background:#f5f3ff; border-radius:12px; display:flex; align-items:center; justify-content:center;">
<svg width="20" height="20" fill="none" stroke="#8b5cf6" stroke-width="2" viewBox="0 0 24 24">
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
</svg>
</div>
</div>
</div>
</div>
{{-- TABLE CARD --}}
<div style="background:#fff; border-radius:16px; border:1px solid #e2e8f0; overflow:hidden;">
{{-- TABLE TOOLBAR --}}
<div class="toolbar-flex" style="padding:18px 24px; border-bottom:1px solid #f1f5f9; display:flex; justify-content:space-between; align-items:center; gap:12px;">
<div style="display:flex; align-items:center; gap:10px;">
<div style="width:32px; height:32px; background:#eff6ff; border-radius:8px; display:flex; align-items:center; justify-content:center;">
<svg width="16" height="16" fill="none" stroke="#2563eb" stroke-width="2" viewBox="0 0 24 24">
<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" />
</svg>
</div>
<div>
<h3 style="margin:0; font-size:15px; font-weight:700; color:#0f172a;">Daftar Pengguna Sistem</h3>
</div>
<span style="background:#eff6ff; color:#2563eb; padding:4px 10px; border-radius:999px; font-size:12px; font-weight:700;">
Total: {{ $stats['total'] }} Pengguna
</span>
</div>
<div class="toolbar-right" style="display:flex; align-items:center; gap:10px;">
{{-- SEARCH --}}
<div style="position:relative; flex:1;">
<svg style="position:absolute; left:10px; top:50%; transform:translateY(-50%); color:#94a3b8;" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
<input type="text" placeholder="Cari nama atau username..." class="search-input"
style="padding:9px 12px 9px 32px; border:1px solid #e2e8f0; border-radius:10px; font-size:13px; color:#475569; outline:none; width:220px; background:#f8fafc; box-sizing:border-box;">
</div>
{{-- TAMBAH --}}
<a href="{{ route('admin.superadmin.user.create') }}" class="btn-tambah"
style="background:#2563eb; color:#fff; text-decoration:none; padding:9px 16px; border-radius:10px; font-size:13px; font-weight:700; display:flex; align-items:center; gap:6px; white-space:nowrap; box-sizing:border-box;">
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
Tambah Pengguna
</a>
</div>
</div>
{{-- TABLE --}}
<div class="table-wrap" style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; min-width:800px;">
<thead>
<tr style="background:#f8fafc;">
<th style="padding:13px 16px; text-align:left; font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:.8px; width:40px;">#</th>
<th style="padding:13px 16px; text-align:left; font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:.8px;">PENGGUNA</th>
<th style="padding:13px 16px; text-align:left; font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:.8px;">USERNAME</th>
<th style="padding:13px 16px; text-align:left; font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:.8px;">ROLE</th>
<th style="padding:13px 16px; text-align:left; font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:.8px;">KEGIATAN</th>
<th style="padding:13px 16px; text-align:left; font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:.8px;">TERDAFTAR</th>
<th style="padding:13px 16px; text-align:center; font-size:11px; font-weight:700; color:#94a3b8; letter-spacing:.8px;">AKSI</th>
</tr>
</thead>
<tbody>
@forelse($users as $index => $user)
<tr style="border-top:1px solid #f1f5f9; transition:background .15s;" onmouseover="this.style.background='#fafbff'" onmouseout="this.style.background='transparent'">
{{-- NO --}}
<td style="padding:16px; color:#94a3b8; font-size:13px; font-weight:600;">
{{ $loop->iteration }}
</td>
{{-- USER --}}
<td style="padding:16px;">
<div style="display:flex; align-items:center; gap:11px;">
@php
$colors = ['#2563eb','#7c3aed','#059669','#dc2626','#d97706'];
$color = $colors[$user->id % count($colors)];
$initials = strtoupper(substr($user->name, 0, 2));
@endphp
<div style="width:38px; height:38px; border-radius:10px; background:{{ $color }}; color:#fff; display:flex; align-items:center; justify-content:center; font-weight:800; font-size:13px; flex-shrink:0;">
{{ $initials }}
</div>
<div>
<div style="font-weight:700; color:#0f172a; font-size:14px;">{{ $user->name }}</div>
<div style="font-size:12px; color:#94a3b8;">ID #{{ $user->id }}</div>
</div>
</div>
</td>
{{-- USERNAME --}}
<td style="padding:16px; color:#475569; font-size:13px;">{{ $user->username }}</td>
{{-- ROLE --}}
<td style="padding:16px;">
@if($user->role == 'superadmin')
<span style="background:#fef9c3; color:#854d0e; padding:5px 12px; border-radius:999px; font-size:12px; font-weight:700;">Super Admin</span>
@elseif($user->role == 'admin')
<span style="background:#dbeafe; color:#1d4ed8; padding:5px 12px; border-radius:999px; font-size:12px; font-weight:700;">Administrator</span>
@else
<span style="background:#dcfce7; color:#15803d; padding:5px 12px; border-radius:999px; font-size:12px; font-weight:700;">Petugas</span>
@endif
</td>
{{-- ACTIVITY --}}
<td style="padding:16px;">
<div style="display:flex; align-items:center; gap:8px;">
<span style="font-weight:700; color:#0f172a; font-size:14px;">{{ $user->activities_count }}</span>
<div style="height:4px; width:40px; background:#f1f5f9; border-radius:4px; overflow:hidden;">
@php $maxAct = max($stats['max_activities'] ?? 1, 1); @endphp
<div style="height:100%; background:#3b82f6; border-radius:4px; width:{{ min(($user->activities_count / $maxAct) * 100, 100) }}%;"></div>
</div>
</div>
</td>
{{-- CREATED --}}
<td style="padding:16px; color:#64748b; font-size:13px;">
{{ $user->created_at->translatedFormat('d M Y') }}
</td>
{{-- ACTION --}}
<td style="padding:16px; text-align:center;">
<div style="display:flex; justify-content:center; gap:6px;">
@php
$editRoute = (session('user')['role'] ?? '') === 'superadmin' ? route('admin.superadmin.user.edit', $user->id) : route('admin.users.edit', $user->id);
@endphp
<a href="{{ $editRoute }}"
style="background:#eff6ff; color:#2563eb; padding:7px 14px; border-radius:8px; text-decoration:none; font-size:12px; font-weight:700; display:inline-flex; align-items:center; gap:4px;">
<svg width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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" />
</svg>
Edit
</a>
@if($user->role !== 'superadmin')
<form action="{{ route('admin.superadmin.user.destroy', $user->id) }}" method="POST"
onsubmit="return confirm('Yakin ingin menghapus pengguna ini?')" style="margin:0;">
@csrf
@method('DELETE')
<button type="submit"
style="background:#fef2f2; color:#dc2626; padding:7px 14px; border:none; border-radius:8px; font-size:12px; font-weight:700; cursor:pointer; display:inline-flex; align-items:center; gap:4px;">
<svg width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<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 6V4h6v2" />
</svg>
Hapus
</button>
</form>
@endif
</div>
</td>
</tr>
@empty
<tr>
<td colspan="7" style="padding:48px; text-align:center; color:#94a3b8; font-size:14px;">
<div style="display:flex; flex-direction:column; align-items:center; gap:8px;">
<svg width="36" height="36" fill="none" stroke="#cbd5e1" stroke-width="1.5" viewBox="0 0 24 24">
<circle cx="12" cy="8" r="4" />
<path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" />
</svg>
Belum ada pengguna terdaftar.
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
{{-- FOOTER / PAGINATION --}}
<div style="padding:14px 24px; border-top:1px solid #f1f5f9; display:flex; justify-content:space-between; align-items:center;">
<p style="font-size:13px; color:#94a3b8; margin:0;">
Menampilkan 1{{ $users->count() }} dari {{ $users->count() }} pengguna
</p>
{{-- Pagination (if using paginate()) --}}
@if(method_exists($users, 'links'))
<div>{{ $users->links() }}</div>
@else
<div style="display:flex; gap:4px;">
<button style="width:32px; height:32px; border:1px solid #e2e8f0; background:#fff; border-radius:8px; font-size:13px; color:#94a3b8; cursor:pointer;">&lt;</button>
<button style="width:32px; height:32px; border:1px solid #2563eb; background:#2563eb; border-radius:8px; font-size:13px; color:#fff; font-weight:700; cursor:pointer;">1</button>
<button style="width:32px; height:32px; border:1px solid #e2e8f0; background:#fff; border-radius:8px; font-size:13px; color:#94a3b8; cursor:pointer;">&gt;</button>
</div>
@endif
</div>
</div>
</div>
@endsection
@@ -0,0 +1,263 @@
@extends('user.layouts.app')
@section('content')
@php
// Logika status agar sinkron dengan database
$status = $activity->status ?? 'on_progres';
$statusLabel = match($status) {
'selesai' => 'DISETUJUI',
'on_progres' => 'ON PROGRES',
'review' => 'REVIEW',
default => strtoupper($status),
};
$statusColor = match($status) {
'selesai' => 'bg-green-100 text-green-700',
'on_progres' => 'bg-blue-100 text-blue-700',
'review' => 'bg-yellow-100 text-yellow-700',
default => 'bg-gray-100 text-gray-700',
};
$fileName = $activity->lampiran ? basename($activity->lampiran) : null;
$shortName = $fileName && strlen($fileName) > 30
? substr($fileName, 0, 30) . '...'
: $fileName;
@endphp
<div class="max-w-6xl mx-auto mt-10 px-4 pb-16">
{{-- HEADER --}}
<div class="mb-8">
<div class="flex gap-3 items-center mb-3">
<span class="{{ $statusColor }} text-xs px-4 py-1.5 rounded-full font-semibold">
{{ $statusLabel }}
</span>
<span class="text-sm text-slate-400">
Terakhir diperbarui:
{{ $activity->updated_at ? \Carbon\Carbon::parse($activity->updated_at)->translatedFormat('d M Y') : '-' }}
</span>
</div>
<h1 class="text-3xl font-bold text-[#0D215C]">{{ $activity->nama_kegiatan }}</h1>
<p class="text-sm text-slate-400">Informasi lengkap aktivitas pegawai</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
{{-- KIRI: KONTEN UTAMA --}}
<div class="lg:col-span-2 bg-white p-7 rounded-2xl shadow-sm border border-slate-100">
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-6 mb-8">
<div>
<p class="text-xs text-slate-400 uppercase tracking-wide mb-1">Nama Pegawai</p>
<p class="font-semibold text-lg text-slate-800">{{ $activity->user->name ?? 'User Tidak Ditemukan' }}</p>
<p class="text-sm text-slate-400">Username: {{ $activity->user->username ?? '-' }}</p>
</div>
<div>
<p class="text-xs text-slate-400 uppercase tracking-wide mb-1">Lokasi</p>
<p class="font-semibold text-slate-800 flex items-center gap-2">
<i data-lucide="map-pin" class="w-4 h-4 text-slate-400"></i>
{{ $activity->lokasi ?? '-' }}
</p>
</div>
<div>
<p class="text-xs text-slate-400 uppercase tracking-wide mb-1">Tanggal Mulai</p>
<p class="font-semibold text-slate-800 flex items-center gap-2">
<i data-lucide="calendar" class="w-4 h-4 text-slate-400"></i>
{{ $activity->tanggal ? \Carbon\Carbon::parse($activity->tanggal)->translatedFormat('d F Y') : '-' }}
</p>
</div>
<div>
<p class="text-xs text-slate-400 uppercase tracking-wide mb-1">Tenggat Waktu</p>
<p class="font-semibold text-slate-800 flex items-center gap-2">
<i data-lucide="clock" class="w-4 h-4 text-slate-400"></i>
@if($activity->tanggal_selesai)
@php
$isOverdue = \Carbon\Carbon::parse($activity->tanggal_selesai)->isPast() && $activity->status !== 'selesai' && $activity->status !== 'telah_ditinjau';
@endphp
<span class="{{ $isOverdue ? 'text-red-600 font-bold' : '' }}">
{{ \Carbon\Carbon::parse($activity->tanggal_selesai)->translatedFormat('d F Y') }}
@if($isOverdue) (Terlambat) @endif
</span>
@else
-
@endif
</p>
</div>
</div>
<hr class="mb-6 border-slate-100">
<div class="mb-8">
<p class="text-xs text-slate-400 uppercase tracking-wide mb-2">Deskripsi Detail</p>
<div class="text-sm text-slate-600 leading-relaxed text-justify">
{{ $activity->deskripsi ?? 'Tidak ada deskripsi tambahan.' }}
</div>
</div>
@if(!empty($activity->status_note))
<div class="mb-8 p-4 bg-blue-50 border border-blue-100 rounded-xl">
<p class="text-xs text-blue-500 uppercase tracking-wide mb-2 font-semibold">Catatan Status Terakhir</p>
<div class="text-sm text-blue-900 leading-relaxed text-justify">
{{ $activity->status_note }}
</div>
</div>
@endif
{{-- 📝 TIMELINE PROGRESS MONITORING --}}
<div class="mb-8">
<p class="text-xs text-slate-400 uppercase tracking-wide mb-4">Log Monitoring Progress</p>
@if(isset($activity->progress) && count($activity->progress) > 0)
<div class="relative border-l-2 border-indigo-100 ml-3 pl-5 space-y-6">
@foreach($activity->progress as $prog)
<div class="relative">
<div class="absolute -left-[27px] bg-indigo-500 h-3 w-3 rounded-full border-2 border-white top-1"></div>
<div class="text-xs text-slate-400 mb-1">
{{ \Carbon\Carbon::parse($prog['created_at'])->format('d M Y, H:i') }}
<span class="font-semibold text-indigo-500">{{ $prog['user']['name'] ?? 'Pegawai' }}</span>
</div>
<div class="text-sm text-slate-700 bg-slate-50 border border-slate-100 p-3 rounded-lg shadow-sm">
{{ $prog['note'] }}
@if(!empty($prog['attachment']))
<div class="mt-3 pt-3 border-t border-slate-200">
<a href="http://127.0.0.1:8000/{{ $prog['attachment'] }}" target="_blank"
class="inline-flex items-center gap-2 px-3 py-1.5 bg-indigo-50 text-indigo-600 text-xs font-semibold rounded-lg hover:bg-indigo-100 transition-colors border border-indigo-100">
<i data-lucide="paperclip" class="w-3.5 h-3.5"></i> Lihat Lampiran Bukti
</a>
</div>
@endif
</div>
</div>
@endforeach
</div>
@else
<div class="text-sm text-slate-500 bg-slate-50 p-4 rounded-xl border border-dashed border-slate-200 text-center">
Belum ada log progress yang dicatat untuk kegiatan ini.
</div>
@endif
@php
$isPetugas = false;
if(isset($activity->petugas)) {
foreach($activity->petugas as $p) {
if($p['id'] == session('user_id')) {
$isPetugas = true;
break;
}
}
}
@endphp
@if($status !== 'selesai' && $isPetugas)
<div class="mt-6 border-t border-slate-100 pt-5">
<form action="{{ route('activity.progress', $activity->id) }}" method="POST" enctype="multipart/form-data">
@csrf
<label class="block text-sm font-semibold text-slate-700 mb-2">Tambahkan Log Progress</label>
<div class="flex flex-col gap-3">
<textarea name="note" required rows="3" placeholder="Contoh: Tim sudah sampai di lokasi survei..." class="w-full bg-slate-50 border border-slate-200 text-slate-800 rounded-xl px-4 py-3 text-sm focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 transition-all shadow-sm resize-y"></textarea>
<div class="flex justify-end gap-3 flex-wrap">
<label class="cursor-pointer bg-slate-50 border border-slate-200 text-slate-500 hover:text-indigo-600 hover:border-indigo-300 px-5 py-2.5 rounded-xl text-sm font-medium transition-all shadow-sm flex items-center gap-2 whitespace-nowrap">
<i data-lucide="image" class="w-4 h-4"></i> Bukti Foto
<input type="file" name="attachment" accept="image/*,.pdf" class="hidden" onchange="this.parentElement.querySelector('span').innerText = this.files[0].name.substring(0,15) + '...'">
<span class="text-xs text-slate-400"></span>
</label>
<button type="submit" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2.5 rounded-xl text-sm font-medium shadow-sm shadow-indigo-200 transition-all flex items-center justify-center gap-2 whitespace-nowrap">
<i data-lucide="send" class="w-4 h-4"></i> Kirim Log
</button>
</div>
</div>
</form>
</div>
@endif
</div>
{{-- ACTION BUTTONS --}}
<div class="flex gap-3 flex-wrap border-t pt-6">
@if($status !== 'selesai' && $isPetugas)
<a href="{{ route('activity.edit', $activity->id) }}"
class="inline-flex items-center gap-2 bg-yellow-500 hover:bg-yellow-600 text-white px-5 py-2.5 rounded-lg text-sm font-medium transition">
<i data-lucide="pencil" class="w-4 h-4"></i> Edit Laporan
</a>
<form action="{{ route('activity.selesai', $activity->id) }}" method="POST">
@csrf
<button type="submit" onclick="return confirm('Tandai kegiatan ini sebagai selesai?')"
class="inline-flex items-center gap-2 bg-green-500 hover:bg-green-600 text-white px-5 py-2.5 rounded-lg text-sm font-medium transition">
<i data-lucide="check" class="w-4 h-4"></i> Selesaikan Kegiatan
</button>
</form>
@endif
</div>
</div>
{{-- KANAN: SIDEBAR DETAIL --}}
<div class="space-y-4">
{{-- Lampiran --}}
<div class="bg-white p-6 rounded-2xl shadow-sm border border-slate-100">
<h4 class="font-semibold mb-4 flex items-center gap-2 text-[#0D215C]">
<i data-lucide="paperclip" class="w-4 h-4"></i> Lampiran
</h4>
@if($activity->lampiran)
<div class="flex items-center gap-3 bg-red-50 border border-red-100 rounded-xl px-4 py-3 mb-4">
<div class="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center">
<i data-lucide="image" class="w-5 h-5 text-red-500"></i>
</div>
<div class="min-w-0">
<p class="text-sm font-medium text-slate-700 truncate">{{ $shortName }}</p>
<p class="text-xs text-slate-400">File Lampiran</p>
</div>
</div>
<div class="grid grid-cols-2 gap-2">
<a href="{{ rtrim(env('BACKEND_API_URL', 'http://127.0.0.1:8000'), '/api') . '/storage/' . $activity->lampiran }}" target="_blank"
class="flex items-center justify-center gap-2 border border-slate-200 hover:bg-slate-50 text-slate-700 py-2 rounded-lg text-sm transition">
<i data-lucide="eye" class="w-4 h-4"></i> Lihat
</a>
<a href="{{ rtrim(env('BACKEND_API_URL', 'http://127.0.0.1:8000'), '/api') . '/storage/' . $activity->lampiran }}" download
class="flex items-center justify-center gap-2 border border-slate-200 hover:bg-slate-50 text-slate-700 py-2 rounded-lg text-sm transition">
<i data-lucide="download" class="w-4 h-4"></i> Unduh
</a>
</div>
@else
<div class="text-center py-4 border-2 border-dashed border-slate-100 rounded-xl">
<p class="text-sm text-slate-400 italic">Tidak ada lampiran</p>
</div>
@endif
</div>
{{-- Metadata --}}
<div class="bg-white p-6 rounded-2xl shadow-sm border border-slate-100">
<h4 class="font-semibold mb-4 text-[#0D215C]">Meta Data</h4>
<div class="space-y-3 text-sm">
<div class="flex justify-between text-slate-600">
<span>ID Laporan</span>
<span class="font-mono text-xs">#ACT-{{ str_pad($activity->id, 5, '0', STR_PAD_LEFT) }}</span>
</div>
<div class="flex justify-between text-slate-600">
<span>Metode</span>
<span>{{ $activity->metode ?? 'Luring' }}</span>
</div>
</div>
</div>
<a href="{{ route('activity.list') }}" class="block text-center text-sm text-blue-600 hover:text-blue-800 transition py-2">
Kembali ke Daftar Laporan
</a>
</div>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
});
</script>
@endsection
@@ -0,0 +1,94 @@
@extends('user.layouts.app')
@section('content')
<div class="max-w-3xl mx-auto mt-10 px-4 pb-20">
{{-- HEADER --}}
<div class="mb-8">
<a href="{{ route('activity.detail', $activity->id) }}" class="text-sm text-blue-600 flex items-center gap-2 mb-4 no-underline hover:underline">
<i data-lucide="arrow-left" class="w-4 h-4"></i> Kembali ke Detail
</a>
<h2 class="text-2xl font-bold text-[#0D215C]">
Edit Laporan Kegiatan
</h2>
<p class="text-sm text-slate-400">Perbarui informasi laporan kegiatan Anda di bawah ini.</p>
</div>
{{-- FORM CARD --}}
<div class="bg-white p-8 rounded-2xl shadow-sm border border-slate-100">
<form action="{{ route('activity.update', $activity->id) }}" method="POST" class="space-y-6">
@csrf
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Nama Kegiatan</label>
<div class="relative">
<input type="text" name="nama_kegiatan"
value="{{ old('nama_kegiatan', $activity->nama_kegiatan) }}"
placeholder="Masukkan nama kegiatan..."
class="w-full p-3 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition" required>
</div>
@error('nama_kegiatan') <span class="text-red-500 text-xs mt-1">{{ $message }}</span> @enderror
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Tanggal Pelaksanaan</label>
<input type="date" name="tanggal"
value="{{ old('tanggal', $activity->tanggal) }}"
class="w-full p-3 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition" required>
@error('tanggal') <span class="text-red-500 text-xs mt-1">{{ $message }}</span> @enderror
</div>
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Lokasi</label>
<input type="text" name="lokasi"
value="{{ old('lokasi', $activity->lokasi) }}"
placeholder="Contoh: Kantor Dinas..."
class="w-full p-3 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition" required>
@error('lokasi') <span class="text-red-500 text-xs mt-1">{{ $message }}</span> @enderror
</div>
</div>
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Deskripsi Kegiatan</label>
<textarea name="deskripsi" rows="5"
placeholder="Jelaskan detail kegiatan yang dilakukan..."
class="w-full p-3 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition">{{ old('deskripsi', $activity->deskripsi) }}</textarea>
@error('deskripsi') <span class="text-red-500 text-xs mt-1">{{ $message }}</span> @enderror
</div>
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Catatan Status Laporan (Node Petugas)</label>
<textarea name="status_note" rows="3"
placeholder="Contoh: Tugas ini sedang berjalan di desa darit..."
class="w-full p-3 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition">{{ old('status_note', $activity->status_note ?? '') }}</textarea>
@error('status_note') <span class="text-red-500 text-xs mt-1">{{ $message }}</span> @enderror
</div>
<div class="flex flex-wrap items-center gap-4 pt-4 border-t border-slate-100">
<button type="submit"
class="bg-[#0D215C] hover:bg-[#0a1a47] text-white px-8 py-3 rounded-xl font-bold transition shadow-lg shadow-blue-900/10 flex items-center gap-2">
<i data-lucide="save" class="w-4 h-4"></i> Simpan Perubahan
</button>
<a href="{{ route('activity.detail', $activity->id) }}"
class="px-8 py-3 border border-slate-200 text-slate-600 rounded-xl font-semibold hover:bg-slate-50 transition">
Batal
</a>
</div>
</form>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
});
</script>
@endsection
@@ -0,0 +1,113 @@
@extends('user.layouts.app')
@section('content')
{{-- PAGE TITLE --}}
<div style="margin-bottom:28px; display: flex; justify-content: space-between; align-items: flex-end; padding: 0 4px; flex-wrap: wrap; gap: 16px;">
<div>
<div style="font-size:26px; font-weight:700; color:#0D215C; font-family:'Outfit', sans-serif;">
Riwayat Aktivitas
</div>
<div style="font-size:14px; color:#6b7280; margin-top:6px; font-family:'Outfit', sans-serif;">
Daftar seluruh laporan kegiatan yang telah Anda kirimkan.
</div>
</div>
<a href="{{ route('input.activity') }}"
style="text-decoration:none; background:#1d4ed8; color:white; padding:10px 24px; border-radius:10px; font-size:13px; font-weight:600; transition:.2s; display: flex; align-items: center; gap: 8px;">
<i data-lucide="plus" style="width: 16px; height: 16px;"></i>
Input Baru
</a>
</div>
{{-- LIST CONTAINER --}}
<div style="display: flex; flex-direction: column; gap: 16px;">
@forelse($activities as $item)
<div class="card" style="padding: 20px; background: white; border-radius: 16px; border: 1px solid #f1f5f9; box-shadow: 0 1px 3px rgba(0,0,0,0.05); transition: .2s;"
onmouseover="this.style.borderColor='#1d4ed8'; this.style.transform='translateY(-2px)'"
onmouseout="this.style.borderColor='#f1f5f9'; this.style.transform='translateY(0)'">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">
<div style="display: flex; gap: 16px; align-items: center;">
{{-- Icon Box --}}
<div style="width: 52px; height: 52px; background: #eff6ff; border-radius: 14px; display: flex; align-items: center; justify-content: center; color: #1d4ed8; flex-shrink: 0;">
<i data-lucide="clipboard-list" style="width: 26px; height: 26px;"></i>
</div>
<div>
<div style="font-size: 17px; font-weight: 700; color: #1e293b; margin-bottom: 6px;">
{{ $item->nama_kegiatan }}
</div>
<div style="display: flex; gap: 15px; align-items: center; flex-wrap: wrap;">
<span style="font-size: 13px; color: #64748b; display: flex; align-items: center; gap: 6px;">
<i data-lucide="user" style="width: 14px; height: 14px;"></i>
<strong style="color: #475569;">{{ $item->user->name ?? 'Pegawai' }}</strong>
</span>
<span style="font-size: 13px; color: #64748b; display: flex; align-items: center; gap: 6px;">
<i data-lucide="calendar" style="width: 14px; height: 14px;"></i>
{{ $item->tanggal ? \Carbon\Carbon::parse($item->tanggal)->translatedFormat('d M Y') : '-' }}
@if(!empty($item->tanggal_selesai))
- {{ \Carbon\Carbon::parse($item->tanggal_selesai)->translatedFormat('d M Y') }}
@endif
</span>
<span style="font-size: 13px; color: #64748b; display: flex; align-items: center; gap: 6px;">
<i data-lucide="map-pin" style="width: 14px; height: 14px;"></i>
{{ $item->lokasi ?? '-' }}
</span>
</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
{{-- Badge Status --}}
@php
$status = $item->status ?? 'on_progres';
$isSelesai = $status === 'selesai';
$isOverdue = !empty($item->tanggal_selesai) && \Carbon\Carbon::parse($item->tanggal_selesai)->isPast() && !$isSelesai && $status !== 'telah_ditinjau';
@endphp
<span style="padding: 6px 14px; border-radius: 99px; font-size: 11px; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase;
{{ $isSelesai ? 'background:#dcfce7; color:#15803d;' : ($isOverdue ? 'background:#fef2f2; color:#dc2626; border:1px solid #fecaca;' : 'background:#eff6ff; color:#1d4ed8;') }}">
{{ $isSelesai ? 'Selesai' : ($isOverdue ? 'Terlambat' : 'On Progres') }}
</span>
{{-- Action Button --}}
<a href="{{ route('activity.detail', $item->id) }}"
style="text-decoration: none; color: #1d4ed8; font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 4px; padding: 8px 12px; border-radius: 8px; transition: .2s;"
onmouseover="this.style.background='#eff6ff'"
onmouseout="this.style.background='transparent'">
Detail
<i data-lucide="chevron-right" style="width: 18px; height: 18px;"></i>
</a>
</div>
</div>
</div>
@empty
{{-- EMPTY STATE --}}
<div style="text-align: center; padding: 80px 20px; background: white; border-radius: 20px; border: 2px dashed #e2e8f0;">
<div style="background: #f8fafc; width: 72px; height: 72px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px;">
<i data-lucide="inbox" style="width: 36px; height: 36px; color: #cbd5e1;"></i>
</div>
<div style="font-size: 18px; font-weight: 700; color: #475569;">Belum Ada Aktivitas</div>
<div style="font-size: 14px; color: #94a3b8; margin-top: 6px; max-width: 300px; margin-left: auto; margin-right: auto;">
Laporan kegiatan yang Anda kirimkan nantinya akan muncul di daftar ini.
</div>
<a href="{{ route('input.activity') }}" style="display: inline-block; margin-top: 24px; color: #1d4ed8; font-weight: 600; font-size: 14px; text-decoration: none;">
Mulai buat laporan pertama
</a>
</div>
@endforelse
</div>
{{-- Script untuk memastikan icon Lucide muncul --}}
<script>
document.addEventListener("DOMContentLoaded", function() {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
});
</script>
@endsection
@@ -0,0 +1,897 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard User</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--primary: #1d4ed8;
--primary-soft: #e0e7ff;
--bg: #f4f6fb;
--card: #ffffff;
--border: #e5e7eb;
--text: #111827;
--muted: #6b7280;
--danger: #dc2626;
--success: #16a34a;
--warning: #f59e0b;
--info: #2563eb;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Inter', sans-serif;
}
body {
background: var(--bg);
display: flex
}
/* ─── SIDEBAR ─── */
.sidebar {
width: 280px;
height: 100vh;
background: #fff;
padding: 24px 18px;
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
position: sticky;
top: 0;
flex-shrink: 0;
}
.logo {
display: flex;
gap: 12px;
align-items: center;
margin-bottom: 18px
}
.logo img {
width: 54px;
height: 54px;
object-fit: contain
}
.logo-text .top,
.logo-text .mid {
font-size: 13px;
font-weight: 700;
line-height: 1.4;
color: #111827
}
.logo-text .bot {
font-size: 11px;
color: var(--muted);
margin-top: 2px
}
.divider {
height: 1px;
background: var(--border);
margin: 14px 0
}
.menu {
display: flex;
flex-direction: column;
gap: 4px
}
.menu a {
padding: 11px 13px;
border-radius: 10px;
text-decoration: none;
color: #374151;
display: flex;
align-items: center;
gap: 10px;
font-size: 14px;
transition: .2s;
}
.menu a:hover {
background: #f3f4f6
}
.menu a.active {
background: var(--primary-soft);
color: var(--primary);
font-weight: 600;
}
.menu a svg {
flex-shrink: 0;
opacity: .7
}
.menu a.active svg {
opacity: 1
}
.bottom {
margin-top: auto;
display: flex;
flex-direction: column;
gap: 4px
}
.menu-item {
padding: 11px 13px;
color: #374151;
text-decoration: none;
border-radius: 10px;
font-size: 14px;
display: flex;
align-items: center;
gap: 10px;
transition: .2s;
}
.menu-item:hover {
background: #f3f4f6
}
.menu-item svg {
opacity: .7
}
.logout-btn {
width: 100%;
padding: 11px 13px;
border: none;
background: none;
color: var(--danger);
cursor: pointer;
text-align: left;
border-radius: 10px;
font-size: 14px;
display: flex;
align-items: center;
gap: 10px;
transition: .2s;
}
.logout-btn:hover {
background: #fef2f2
}
/* ─── MAIN ─── */
.main {
flex: 1;
padding: 28px 32px;
overflow-y: auto;
height: 100vh
}
/* ─── HEADER ─── */
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 28px;
}
.search-wrap {
position: relative;
width: 340px
}
.search-wrap svg {
position: absolute;
left: 13px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
color: var(--muted);
}
.search {
width: 100%;
padding: 10px 14px 10px 40px;
border: 1px solid var(--border);
border-radius: 12px;
transition: .2s;
font-size: 14px;
background: #fff;
}
.search:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(29, 78, 216, .08);
}
/* ─── USER ─── */
.user {
display: flex;
align-items: center;
gap: 14px
}
.avatar {
width: 40px;
height: 40px;
background: #1e3a8a;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
font-weight: 700;
font-size: 15px;
flex-shrink: 0;
}
/* ─── NOTIF ─── */
.notif {
position: relative;
cursor: pointer
}
.notif-btn {
width: 40px;
height: 40px;
border: 1px solid var(--border);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
cursor: pointer;
transition: .2s;
}
.notif-btn:hover {
background: #f3f4f6
}
.badge {
position: absolute;
top: -5px;
right: -5px;
background: #ef4444;
color: #fff;
font-size: 11px;
border-radius: 999px;
padding: 2px 6px;
font-weight: 600;
min-width: 20px;
text-align: center;
}
.dropdown {
position: absolute;
right: 0;
top: 50px;
width: 320px;
background: #fff;
border: 1px solid var(--border);
border-radius: 14px;
box-shadow: 0 10px 30px rgba(0, 0, 0, .1);
display: none;
z-index: 100;
}
.dropdown.show {
display: block
}
.dropdown-header {
padding: 13px 16px;
font-weight: 600;
font-size: 14px;
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
}
.dropdown-header a {
font-size: 12px;
color: var(--primary);
text-decoration: none;
font-weight: 500
}
.dropdown-item {
padding: 13px 16px;
border-bottom: 1px solid var(--border);
font-size: 13px;
line-height: 1.5;
color: var(--text);
}
.dropdown-item:last-child {
border-bottom: none
}
.dropdown-item.unread {
background: #eef2ff
}
.dropdown-empty {
padding: 24px;
text-align: center;
color: var(--muted);
font-size: 13px
}
/* ─── PAGE TITLE ─── */
.page-title {
font-size: 24px;
font-weight: 700;
margin-bottom: 4px;
color: var(--text)
}
.page-subtitle {
color: var(--muted);
font-size: 14px;
margin-bottom: 22px
}
/* ─── CARDS ─── */
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin-bottom: 24px
}
.card {
background: #fff;
padding: 20px 22px;
border-radius: 14px;
border: 1px solid var(--border);
transition: .2s;
}
.card:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 0, 0, .06)
}
.card h4 {
font-size: 11px;
font-weight: 600;
letter-spacing: .05em;
margin-bottom: 8px;
}
.card h2 {
font-size: 32px;
font-weight: 700
}
.card.total h4,
.card.total h2 {
color: var(--info)
}
.card.proses h4,
.card.proses h2 {
color: var(--warning)
}
.card.selesai h4,
.card.selesai h2 {
color: var(--success)
}
.card-icon {
width: 36px;
height: 36px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12px;
}
.card.total .card-icon {
background: #dbeafe
}
.card.proses .card-icon {
background: #fef3c7
}
.card.selesai .card-icon {
background: #dcfce7
}
/* ─── LIST ─── */
.list {
background: #fff;
border-radius: 14px;
border: 1px solid var(--border);
overflow: hidden;
}
.list-header {
padding: 16px 20px;
font-weight: 600;
font-size: 14px;
border-bottom: 1px solid var(--border);
background: #fafafa;
display: flex;
justify-content: space-between;
align-items: center;
}
.list-header a {
font-size: 13px;
color: var(--primary);
text-decoration: none;
font-weight: 600;
}
.list-header a:hover {
text-decoration: underline
}
.item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid var(--border);
transition: .2s;
}
.item:last-child {
border-bottom: none
}
.item:hover {
background: #f9fafb
}
.item-left strong {
display: block;
margin-bottom: 3px;
font-size: 14px
}
.item-left small {
color: var(--muted);
font-size: 12px
}
.badge-status {
padding: 5px 12px;
border-radius: 999px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
.badge-success {
background: #dcfce7;
color: var(--success)
}
.badge-warning {
background: #fef3c7;
color: #b45309
}
.badge-info {
background: #dbeafe;
color: #1d4ed8
}
.badge-danger {
background: #fee2e2;
color: #dc2626
}
/* ─── EMPTY STATE ─── */
.empty-state {
padding: 48px 20px;
text-align: center;
color: var(--muted);
}
.empty-state svg {
margin: 0 auto 12px;
display: block;
opacity: .35
}
.empty-state p {
font-size: 14px
}
/* ─── NO RESULT ─── */
.no-result {
display: none;
padding: 32px 20px;
text-align: center;
color: var(--muted);
font-size: 14px;
}
/* ─── RESPONSIVE ─── */
@media (max-width: 1024px) {
.cards { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
body { flex-direction: column; }
.sidebar {
width: 100%;
height: auto;
position: relative;
border-right: none;
border-bottom: 1px solid var(--border);
padding: 16px;
flex-direction: column;
}
.logo {
justify-content: center;
margin-bottom: 12px;
}
.divider { display: none; }
.menu {
flex-direction: row;
flex-wrap: wrap;
overflow-x: visible;
gap: 8px;
padding-bottom: 8px;
}
.menu a { white-space: nowrap; justify-content: center; flex: 1 1 calc(50% - 8px); text-align: center; font-size: 13px; padding: 10px; }
.bottom {
flex-direction: row;
margin-top: 8px;
gap: 8px;
border-top: 1px solid var(--border);
padding-top: 12px;
}
.bottom a, .bottom button { white-space: nowrap; justify-content: center; flex: 1 1 calc(50% - 8px); font-size: 13px; padding: 10px; }
.main { padding: 20px 16px; height: auto; }
.header { flex-direction: column-reverse; align-items: flex-start; gap: 20px; margin-bottom: 20px; }
.search-wrap { width: 100%; }
.user { width: 100%; justify-content: space-between; }
.dropdown { width: 300px; left: -10px; right: auto; top: 55px; max-width: calc(100vw - 32px); }
.cards { grid-template-columns: 1fr; gap: 12px; }
.item { flex-direction: column; align-items: flex-start; gap: 12px; }
}
</style>
</head>
<body>
<!-- ═══ SIDEBAR ═══ -->
<div class="sidebar">
<div class="logo">
<img src="{{ asset('Kalimantan-Barat-Logo-Vector.png') }}" alt="Logo">
<div class="logo-text">
<div class="top">DINAS TENAGA KERJA</div>
<div class="mid">DAN TRANSMIGRASI</div>
<div class="bot">PROVINSI KALIMANTAN BARAT</div>
</div>
</div>
<div class="divider"></div>
<div class="menu">
<a href="{{ route('user.dashboard') }}"
class="{{ request()->routeIs('user.dashboard') ? 'active' : '' }}">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="7" height="7" rx="1" />
<rect x="13" y="3" width="8" height="7" rx="1" />
<rect x="13" y="13" width="8" height="8" rx="1" />
<rect x="3" y="13" width="7" height="8" rx="1" />
</svg>
Dashboard
</a>
<a href="{{ route('input.activity') }}"
class="{{ request()->routeIs('input.activity') ? 'active' : '' }}">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<path d="M11 5H6a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-5" />
<path d="M17.5 3.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 8.5-8.5z" />
</svg>
Input Aktivitas
</a>
<a href="{{ route('activity.list') }}"
class="{{ request()->routeIs('activity.list') ? 'active' : '' }}">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2" />
<rect x="9" y="3" width="6" height="4" rx="1" />
<path d="M9 12h6M9 16h4" />
</svg>
Daftar Aktivitas
</a>
</div>
<div class="bottom">
<a href="{{ route('settings') }}" class="menu-item">
<svg width="18" height="18" 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" />
</svg>
Pengaturan
</a>
<form method="POST" action="{{ route('logout') }}">
@csrf
<button class="logout-btn" type="submit">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" y1="12" x2="9" y2="12" />
</svg>
Logout
</button>
</form>
</div>
</div>
<!-- ═══ MAIN ═══ -->
<div class="main">
<!-- HEADER -->
<div class="header">
<div class="search-wrap">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.35-4.35" />
</svg>
<input type="text" class="search" placeholder="Cari aktivitas..."
oninput="filterAktivitas(this.value)">
</div>
<div class="user">
<!-- NOTIF -->
<div class="notif">
<div class="notif-btn" onclick="toggleNotif()">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" />
<path d="M13.73 21a2 2 0 0 1-3.46 0" />
</svg>
</div>
@if($unreadCount > 0)
<div class="badge">{{ $unreadCount }}</div>
@endif
<div class="dropdown" id="notifDropdown">
<div class="dropdown-header">
Notifikasi
@if(count($notifications) > 0)
<a href="#" onclick="markAllAsRead(event)">Tandai semua dibaca</a>
@endif
</div>
<div id="notifListContainer">
@forelse($notifications as $n)
<div class="dropdown-item {{ !$n['read_at'] ? 'unread' : '' }}">
{{ $n['data']['message'] ?? 'Ada notifikasi baru' }}
<br><small style="color:var(--muted); font-size:11px;">{{ \Carbon\Carbon::parse($n['created_at'])->diffForHumans() }}</small>
</div>
@empty
<div class="dropdown-empty">Tidak ada notifikasi</div>
@endforelse
</div>
</div>
</div>
<!-- USER INFO -->
<div>
<strong style="font-size:14px">
{{ session('user')['name'] ?? 'User' }}
</strong><br>
<small style="color:var(--muted);font-size:12px">Pegawai</small>
</div>
<div class="avatar">
{{ strtoupper(substr(session('user')['name'] ?? 'U', 0, 1)) }}
</div>
</div>{{-- end .user --}}
</div>{{-- end .header --}}
<!-- PAGE TITLE -->
<div class="page-title">Dashboard Monitoring</div>
<div class="page-subtitle">Pantau aktivitas kamu</div>
<!-- CARDS -->
<div class="cards">
<div class="card total">
<div class="card-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="#2563eb" stroke-width="2">
<rect x="3" y="3" width="7" height="7" rx="1" />
<rect x="13" y="3" width="8" height="7" rx="1" />
<rect x="13" y="13" width="8" height="8" rx="1" />
<rect x="3" y="13" width="7" height="8" rx="1" />
</svg>
</div>
<h4>TOTAL</h4>
<h2>{{ $activities->count() }}</h2>
</div>
<div class="card proses">
<div class="card-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="#f59e0b" stroke-width="2">
<circle cx="12" cy="12" r="10" />
<polyline points="12 6 12 12 16 14" />
</svg>
</div>
<h4>ON PROGRESS</h4>
<h2>{{ $onProgres }}</h2>
</div>
<div class="card selesai">
<div class="card-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none"
stroke="#16a34a" stroke-width="2">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
</div>
<h4>SELESAI</h4>
<h2>{{ $selesai }}</h2>
</div>
</div>
<!-- RECENT ACTIVITIES -->
<div class="list">
<div class="list-header">
<span>Recent Activities</span>
<a href="{{ route('activity.list') }}">Lihat Semua </a>
</div>
<div id="activity-list">
@forelse($activities->take(5) as $item)
<div class="item" data-name="{{ strtolower($item->nama_kegiatan) }}">
<div class="item-left">
<strong>{{ $item->nama_kegiatan }}</strong>
<small>
{{ $item->user->name ?? 'Pegawai' }}
&nbsp;·&nbsp;
{{ \Carbon\Carbon::parse($item->tanggal ?? $item->created_at)->translatedFormat('d M Y') }}
@if(!empty($item->tanggal_selesai))
- {{ \Carbon\Carbon::parse($item->tanggal_selesai)->translatedFormat('d M Y') }}
@endif
@if(!empty($item->lokasi))
&nbsp;·&nbsp; {{ $item->lokasi }}
@endif
</small>
</div>
<div>
@php
$isOverdue = !empty($item->tanggal_selesai) && \Carbon\Carbon::parse($item->tanggal_selesai)->isPast() && $item->status !== 'selesai' && $item->status !== 'telah_ditinjau';
@endphp
@if($item->status == 'selesai')
<span class="badge-status badge-success">Selesai</span>
@elseif(!empty($item->reviewed_at) || $item->status == 'ditinjau' || $item->status == 'telah_ditinjau')
<span class="badge-status badge-info">Ditinjau</span>
@elseif($item->status == 'ditolak')
<span class="badge-status badge-danger">Ditolak</span>
@elseif($isOverdue)
<span class="badge-status badge-danger" style="background:#fef2f2; color:#dc2626; border-color:#fecaca;">Terlambat</span>
@else
<span class="badge-status badge-warning">On Progress</span>
@endif
</div>
</div>
@empty
<div class="empty-state">
<svg width="44" height="44" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.5">
<path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2" />
<rect x="9" y="3" width="6" height="4" rx="1" />
<path d="M9 12h6M9 16h4" />
</svg>
<p>Belum ada aktivitas yang diinput.</p>
<a href="{{ route('input.activity') }}"
style="display:inline-block;margin-top:12px;padding:8px 18px;
background:var(--primary);color:#fff;border-radius:8px;
text-decoration:none;font-size:13px;font-weight:500">
+ Input Aktivitas
</a>
</div>
@endforelse
</div>
<!-- No result saat search -->
<div class="no-result" id="no-result">
Tidak ada aktivitas yang cocok dengan pencarian.
</div>
</div>
</div>{{-- end .list --}}
</div>{{-- end .main --}}
<script>
// ─── TOGGLE NOTIF ───
function toggleNotif() {
document.getElementById("notifDropdown").classList.toggle("show");
}
document.addEventListener('click', function(e) {
const notif = document.querySelector('.notif');
if (notif && !notif.contains(e.target)) {
document.getElementById('notifDropdown').classList.remove('show');
}
});
async function markAllAsRead(e) {
e.preventDefault();
try {
await fetch('/user/notifications-api/read', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'Content-Type': 'application/json'
}
});
// Hapus badge dan ganti class unread
const badge = document.querySelector('.badge');
if (badge) badge.style.display = 'none';
document.querySelectorAll('.dropdown-item.unread').forEach(el => {
el.classList.remove('unread');
});
} catch (e) {
console.error(e);
}
}
// ─── FILTER SEARCH ───
function filterAktivitas(keyword) {
const items = document.querySelectorAll('#activity-list .item');
const noResult = document.getElementById('no-result');
keyword = keyword.toLowerCase().trim();
let visibleCount = 0;
items.forEach(item => {
const name = item.getAttribute('data-name') || '';
if (name.includes(keyword)) {
item.style.display = 'flex';
visibleCount++;
} else {
item.style.display = 'none';
}
});
if (visibleCount === 0 && items.length > 0) {
noResult.style.display = 'block';
} else {
noResult.style.display = 'none';
}
}
</script>
</body>
</html>
@@ -0,0 +1,123 @@
@extends('user.layouts.app')
@section('content')
{{-- PAGE TITLE --}}
<div style="margin-bottom:28px;">
<div style="font-size:26px; font-weight:700; color:#111827; font-family:'Outfit', sans-serif;">
Input Laporan Kegiatan
</div>
<div style="font-size:14px; color:#6b7280; margin-top:6px; font-family:'Outfit', sans-serif;">
Pastikan data yang dimasukkan sudah sesuai dengan dokumentasi lapangan.
</div>
</div>
@if ($errors->any())
<div style="background-color: #fee2e2; border-left: 4px solid #ef4444; padding: 16px; margin-bottom: 24px; border-radius: 4px;">
<div style="color: #b91c1c; font-weight: 600; margin-bottom: 8px;">Terdapat kesalahan pada input Anda:</div>
<ul style="color: #b91c1c; font-size: 14px; margin: 0; padding-left: 20px;">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('activities.store') }}" method="POST" enctype="multipart/form-data">
@csrf
{{-- DATA PEGAWAI --}}
<div class="card">
<div style="font-size:13px; font-weight:600; color:#1d4ed8; margin-bottom:16px;
padding-bottom:12px; border-bottom:1px solid #e5e7eb; letter-spacing:0.04em;">
DATA PEGAWAI
</div>
<div class="form-grid">
<div>
<label class="label">Nama Pegawai</label>
<input type="text" value="{{ session('user')['name'] ?? 'Guest' }}" class="input readonly" readonly>
</div>
<div>
<label class="label">Username</label>
<input type="text" value="{{ session('user')['username'] ?? '-' }}" class="input readonly" readonly>
</div>
</div>
</div>
{{-- DETAIL KEGIATAN --}}
<div class="card">
<div style="font-size:13px; font-weight:600; color:#1d4ed8; margin-bottom:16px;
padding-bottom:12px; border-bottom:1px solid #e5e7eb; letter-spacing:0.04em;">
DETAIL KEGIATAN
</div>
<div>
<label class="label">Judul Kegiatan</label>
<input type="text" name="nama_kegiatan" class="input" placeholder="Monitoring perusahaan..." required>
</div>
<div class="form-grid" style="margin-top:16px;">
<div>
<label class="label">Tanggal</label>
<input type="date" name="tanggal" class="input" required>
</div>
<div>
<label class="label">Lokasi</label>
<input type="text" name="lokasi" class="input" placeholder="Kota / Alamat" required>
</div>
</div>
<div style="margin-top:16px;">
<label class="label">Detail Kegiatan</label>
<textarea name="deskripsi" class="textarea" placeholder="Tulis laporan lengkap di sini..." required></textarea>
</div>
</div>
{{-- UPLOAD --}}
<div class="card">
<div style="font-size:13px; font-weight:600; color:#1d4ed8; margin-bottom:16px;
padding-bottom:12px; border-bottom:1px solid #e5e7eb; letter-spacing:0.04em;">
LAMPIRAN DOKUMENTASI
</div>
<label class="upload-box" id="upload-label">
<input type="file" name="image" id="file-input" accept=".pdf,.jpg,.jpeg,.png" hidden>
{{-- Icon Upload --}}
<svg width="36" height="36" viewBox="0 0 24 24" fill="none"
stroke="#9ca3af" stroke-width="1.5" style="margin:0 auto 10px;">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" y1="3" x2="12" y2="15"/>
</svg>
<p style="font-weight:600; font-size:14px; color:#374151; margin-bottom:4px;" id="file-name">
Klik untuk upload file
</p>
<small style="color:#9ca3af; font-size:12px;">PDF / JPG / PNG · Maksimal 2MB</small>
</label>
</div>
{{-- SUBMIT --}}
<button class="btn" type="submit">
Kirim Laporan
</button>
</form>
{{-- Script: tampilkan nama file setelah dipilih --}}
<script>
document.getElementById('file-input').addEventListener('change', function() {
const fileName = this.files[0] ? this.files[0].name : 'Klik untuk upload file';
document.getElementById('file-name').textContent = fileName;
});
</script>
@endsection
@@ -0,0 +1,215 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Panel Petugas Disnakertrans Prov. Kalbar</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
/* ─── RESET + FONT ─── */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Outfit', sans-serif;
}
body {
background: #F2F5FB;
color: #334155;
}
/* ─── SCROLLBAR ─── */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #f1f5f9; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
/* ─── VARIABLES ─── */
:root {
--primary: #1d4ed8;
--primary-soft: #e0e7ff;
--border: #e5e7eb;
--text: #111827;
--muted: #6b7280;
}
/* ─── CARD ─── */
.card {
background: #fff;
border: 1px solid var(--border);
border-radius: 16px;
padding: 28px;
margin-bottom: 20px;
}
/* ─── FORM GRID ─── */
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
/* ─── LABEL ─── */
.label {
font-size: 12px;
font-weight: 600;
color: var(--muted);
margin-bottom: 6px;
display: block;
letter-spacing: 0.03em;
}
/* ─── INPUT ─── */
.input {
width: 100%;
padding: 12px 14px;
border: 1px solid var(--border);
border-radius: 10px;
font-size: 14px;
font-family: 'Outfit', sans-serif;
background: #fff;
color: var(--text);
transition: .2s;
}
.input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(29,78,216,.1);
}
.readonly {
background: #f3f4f6;
color: #6b7280;
cursor: not-allowed;
}
/* ─── TEXTAREA ─── */
.textarea {
width: 100%;
padding: 14px;
border: 1px solid var(--border);
border-radius: 10px;
font-size: 14px;
font-family: 'Outfit', sans-serif;
color: var(--text);
min-height: 140px;
resize: vertical;
transition: .2s;
}
.textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(29,78,216,.1);
}
/* ─── UPLOAD BOX ─── */
.upload-box {
border: 2px dashed var(--border);
padding: 30px;
text-align: center;
border-radius: 14px;
cursor: pointer;
display: block;
transition: .2s;
}
.upload-box:hover {
background: #f9fafb;
border-color: var(--primary);
}
/* ─── BUTTON ─── */
.btn {
width: 100%;
padding: 14px;
border: none;
border-radius: 12px;
background: var(--primary);
color: #fff;
font-weight: 600;
font-size: 15px;
font-family: 'Outfit', sans-serif;
cursor: pointer;
transition: .2s;
letter-spacing: 0.02em;
}
.btn:hover {
background: #1e40af;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(29,78,216,.3);
}
.btn:active {
transform: translateY(0);
}
/* ─── RESPONSIVE ─── */
@media (max-width: 768px) {
.form-grid {
grid-template-columns: 1fr;
}
main {
padding: 20px 0 !important;
}
.card {
padding: 20px;
}
}
</style>
</head>
<body>
@include('user.layouts.navbar')
<main style="padding: 40px 0;">
<div style="max-width: 860px; margin: auto; padding: 0 24px;">
@yield('content')
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
lucide.createIcons();
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('[onclick^="return confirm"]').forEach(function(btn) {
const match = btn.getAttribute('onclick').match(/confirm\('([^']+)'\)/);
if (match) {
const message = match[1];
btn.removeAttribute('onclick');
btn.addEventListener('click', function(e) {
e.preventDefault();
const form = btn.closest('form');
Swal.fire({
title: 'Konfirmasi',
text: message,
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3b82f6',
cancelButtonColor: '#64748b',
confirmButtonText: 'Ya, Lanjutkan',
cancelButtonText: 'Batal',
reverseButtons: true,
customClass: {
confirmButton: 'rounded-xl',
cancelButton: 'rounded-xl mr-2'
}
}).then((result) => {
if (result.isConfirmed) {
if (form) {
form.submit();
} else if(btn.getAttribute('href')) {
window.location.href = btn.getAttribute('href');
}
}
});
});
}
});
});
</script>
</body>
</html>
@@ -0,0 +1,136 @@
<nav class="bg-[#f8fafc] border-b border-slate-200 font-['Outfit'] sticky top-0 z-50 shadow-sm">
<div class="max-w-[1200px] mx-auto px-4 md:px-6 lg:px-10">
<div class="flex items-center justify-between h-[70px]">
<!-- LEFT: LOGO -->
<div class="flex items-center gap-2 md:gap-3">
<img src="{{ asset('Kalimantan-Barat-Logo-Vector.png') }}" class="h-9 md:h-[42px] w-auto object-contain" alt="Logo Kalbar">
<div class="leading-[1.2] border-l-2 border-slate-200 pl-2 md:pl-3">
<div class="font-bold text-[11px] md:text-[14px] text-blue-900 tracking-[0.02em]">
DINAS TENAGA KERJA DAN TRANSMIGRASI
</div>
<div class="text-[8px] md:text-[11px] text-slate-500 font-medium">
PROVINSI KALIMANTAN BARAT
</div>
</div>
</div>
<!-- Hamburger Button (Mobile) -->
<div class="flex md:hidden">
<button type="button" id="user-menu-btn" class="text-slate-500 hover:text-blue-900 focus:outline-none p-2 rounded-md hover:bg-slate-200 transition-colors">
<i data-lucide="menu" class="w-6 h-6"></i>
</button>
</div>
<!-- CENTER & RIGHT: NAVIGATION (Desktop) -->
<div class="hidden md:flex items-center gap-6">
<div class="flex items-center gap-2 text-[14px]">
<a href="{{ route('user.dashboard') }}"
class="flex items-center gap-1.5 px-4 py-2 rounded-lg transition-all duration-200 {{ request()->routeIs('user.dashboard') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-500 font-medium hover:bg-slate-100 hover:text-blue-800' }}">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> Dashboard
</a>
<a href="{{ route('input.activity') }}"
class="flex items-center gap-1.5 px-4 py-2 rounded-lg transition-all duration-200 {{ request()->routeIs('input.activity') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-500 font-medium hover:bg-slate-100 hover:text-blue-800' }}">
<i data-lucide="edit" class="w-4 h-4"></i> Input Kegiatan
</a>
<a href="{{ route('activity.list') }}"
class="flex items-center gap-1.5 px-4 py-2 rounded-lg transition-all duration-200 {{ request()->routeIs('activity.list') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-500 font-medium hover:bg-slate-100 hover:text-blue-800' }}">
<i data-lucide="folder" class="w-4 h-4"></i> Kegiatan Saya
</a>
<a href="{{ route('settings') ?? '#' }}"
class="flex items-center gap-1.5 px-4 py-2 rounded-lg transition-all duration-200 {{ request()->routeIs('settings') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-500 font-medium hover:bg-slate-100 hover:text-blue-800' }}">
<i data-lucide="settings" class="w-4 h-4"></i> Pengaturan
</a>
</div>
<div class="w-px h-8 bg-slate-300"></div>
<div class="flex items-center gap-2.5">
<div class="w-[38px] h-[38px] rounded-full bg-blue-900 text-white flex items-center justify-center font-bold text-[16px]">
{{ strtoupper(substr(session('user')['name'] ?? 'U', 0, 1)) }}
</div>
<div class="leading-[1.2]">
<div class="font-semibold text-[14px] text-slate-900">
{{ session('user')['name'] ?? 'User' }}
</div>
<div class="text-[11px] text-slate-500 font-medium">
USER
</div>
</div>
<form method="POST" action="{{ route('logout') }}" class="ml-2 m-0">
@csrf
<button type="submit" class="bg-transparent border-none cursor-pointer text-red-500 p-1.5 rounded-md hover:bg-red-50 transition-colors" title="Logout">
<i data-lucide="log-out" class="w-[18px] h-[18px]"></i>
</button>
</form>
</div>
</div>
</div>
</div>
<!-- Mobile Menu Panel -->
<div id="user-mobile-menu" class="hidden md:hidden bg-[#f8fafc] border-t border-slate-200 shadow-xl absolute w-full left-0 pb-4">
<div class="px-4 py-3 flex flex-col gap-2">
<a href="{{ route('user.dashboard') }}"
class="flex items-center gap-3 px-4 py-3 rounded-lg transition-all duration-200 {{ request()->routeIs('user.dashboard') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-600 font-medium hover:bg-slate-200' }}">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> Dashboard
</a>
<a href="{{ route('input.activity') }}"
class="flex items-center gap-3 px-4 py-3 rounded-lg transition-all duration-200 {{ request()->routeIs('input.activity') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-600 font-medium hover:bg-slate-200' }}">
<i data-lucide="edit" class="w-4 h-4"></i> Input Kegiatan
</a>
<a href="{{ route('activity.list') }}"
class="flex items-center gap-3 px-4 py-3 rounded-lg transition-all duration-200 {{ request()->routeIs('activity.list') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-600 font-medium hover:bg-slate-200' }}">
<i data-lucide="folder" class="w-4 h-4"></i> Kegiatan Saya
</a>
<a href="{{ route('settings') ?? '#' }}"
class="flex items-center gap-3 px-4 py-3 rounded-lg transition-all duration-200 {{ request()->routeIs('settings') ? 'text-blue-800 bg-indigo-50 font-semibold' : 'text-slate-600 font-medium hover:bg-slate-200' }}">
<i data-lucide="settings" class="w-4 h-4"></i> Pengaturan
</a>
<div class="h-px w-full bg-slate-200 my-2"></div>
<div class="flex items-center justify-between px-2">
<div class="flex items-center gap-3">
<div class="w-[38px] h-[38px] rounded-full bg-blue-900 text-white flex items-center justify-center font-bold text-[16px]">
{{ strtoupper(substr(session('user')['name'] ?? 'U', 0, 1)) }}
</div>
<div class="leading-[1.2]">
<div class="font-semibold text-[14px] text-slate-900">
{{ session('user')['name'] ?? 'User' }}
</div>
<div class="text-[11px] text-slate-500 font-medium">
USER
</div>
</div>
</div>
<form method="POST" action="{{ route('logout') }}" class="m-0">
@csrf
<button type="submit" class="bg-transparent border-none cursor-pointer text-red-500 p-2 rounded-md hover:bg-red-50 transition-colors flex items-center gap-2" title="Logout">
<i data-lucide="log-out" class="w-5 h-5"></i>
</button>
</form>
</div>
</div>
</div>
</nav>
<script>
document.addEventListener('DOMContentLoaded', function() {
const btn = document.getElementById('user-menu-btn');
const menu = document.getElementById('user-mobile-menu');
if(btn && menu) {
btn.addEventListener('click', function(e) {
e.stopPropagation();
menu.classList.toggle('hidden');
lucide.createIcons();
});
document.addEventListener('click', function(e) {
if(!menu.contains(e.target) && !btn.contains(e.target)) {
menu.classList.add('hidden');
}
});
}
});
</script>
@@ -0,0 +1,173 @@
@php
$role = session('user')['role'] ?? 'user';
$layout = in_array($role, ['admin', 'superadmin']) ? 'admin.layouts.app' : 'user.layouts.app';
if ($role === 'superadmin') {
$dashboardRoute = route('admin.superadmin.dashboard');
} elseif ($role === 'admin') {
$dashboardRoute = route('admin.dashboard');
} else {
$dashboardRoute = route('user.dashboard');
}
@endphp
@extends($layout)
@section('content')
<div class="max-w-4xl mx-auto mt-10 px-4 pb-20">
{{-- HEADER --}}
<div class="mb-8">
<a href="{{ $dashboardRoute }}" class="inline-flex items-center gap-2 text-sm text-slate-500 hover:text-[#0D215C] font-semibold mb-4 transition">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path d="M19 12H5M12 5l-7 7 7 7"/></svg>
Kembali ke Dashboard
</a>
<h2 class="text-2xl font-bold text-[#0D215C]">
Pengaturan Profil
</h2>
<p class="text-sm text-slate-400">Kelola informasi akun dan kata sandi Anda.</p>
</div>
@if(session('success'))
<div class="mb-6 p-4 bg-green-100 border border-green-200 text-green-700 rounded-xl text-sm font-medium">
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="mb-6 p-4 bg-red-100 border border-red-200 text-red-700 rounded-xl text-sm font-medium">
{{ session('error') }}
</div>
@endif
@if($errors->any())
<div class="mb-6 p-4 bg-red-100 border border-red-200 text-red-700 rounded-xl text-sm font-medium">
<ul class="list-disc list-inside">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="grid grid-cols-1 gap-8">
{{-- FORM INFORMASI PROFIL --}}
<div class="bg-white p-8 rounded-2xl shadow-sm border border-slate-100">
<h4 class="text-lg font-bold text-[#0D215C] mb-6 flex items-center gap-2">
<i data-lucide="user" class="w-5 h-5"></i> Informasi Pribadi
</h4>
<form action="{{ route('settings.update') }}" method="POST" class="space-y-5">
@csrf
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Nama Lengkap</label>
<input type="text" name="name" value="{{ session('user')['name'] ?? '' }}"
class="w-full p-3 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition" readonly>
</div>
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Username <span class="text-red-500">*</span></label>
<input type="text" name="username" value="{{ session('user')['username'] ?? '' }}"
class="w-full p-3 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition">
</div>
</div>
<div class="pt-4">
<button type="submit" class="bg-[#0D215C] hover:bg-[#0a1a47] text-white px-8 py-3 rounded-xl font-bold transition shadow-lg shadow-blue-900/10">
Simpan Perubahan
</button>
</div>
</form>
</div>
@if($role !== 'user')
{{-- FORM GANTI PASSWORD --}}
<div class="bg-white p-8 rounded-2xl shadow-sm border border-slate-100">
<h4 class="text-lg font-bold text-[#0D215C] mb-6 flex items-center gap-2">
<i data-lucide="lock" class="w-5 h-5"></i> Keamanan Akun
</h4>
<form action="{{ route('settings.update') }}" method="POST" class="space-y-5">
@csrf
<input type="hidden" name="username" value="{{ session('user')['username'] ?? '' }}">
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Kata Sandi Saat Ini</label>
<div class="relative">
<input type="password" name="current_password" id="current_password" autocomplete="off"
class="w-full p-3 pr-10 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition">
<button type="button" onclick="togglePassword('current_password', this)" class="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-blue-500 focus:outline-none">
<i data-lucide="eye" class="w-5 h-5 eye-icon"></i>
<i data-lucide="eye-off" class="w-5 h-5 eye-off-icon hidden"></i>
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Kata Sandi Baru</label>
<div class="relative">
<input type="password" name="password" id="password"
class="w-full p-3 pr-10 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition">
<button type="button" onclick="togglePassword('password', this)" class="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-blue-500 focus:outline-none">
<i data-lucide="eye" class="w-5 h-5 eye-icon"></i>
<i data-lucide="eye-off" class="w-5 h-5 eye-off-icon hidden"></i>
</button>
</div>
</div>
<div>
<label class="text-sm font-semibold text-slate-700 block mb-2">Konfirmasi Kata Sandi</label>
<div class="relative">
<input type="password" name="password_confirmation" id="password_confirmation"
class="w-full p-3 pr-10 rounded-xl bg-slate-50 border border-slate-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 outline-none transition">
<button type="button" onclick="togglePassword('password_confirmation', this)" class="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-blue-500 focus:outline-none">
<i data-lucide="eye" class="w-5 h-5 eye-icon"></i>
<i data-lucide="eye-off" class="w-5 h-5 eye-off-icon hidden"></i>
</button>
</div>
</div>
</div>
<div class="pt-4">
<button type="submit" class="bg-white border border-slate-200 hover:bg-slate-50 text-[#0D215C] px-8 py-3 rounded-xl font-bold transition">
Perbarui Kata Sandi
</button>
</div>
</form>
</div>
@endif
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
});
function togglePassword(inputId, btn) {
const input = document.getElementById(inputId);
const eye = btn.querySelector('.eye-icon');
const eyeOff = btn.querySelector('.eye-off-icon');
if (input.type === 'password') {
input.type = 'text';
eye.classList.add('hidden');
eyeOff.classList.remove('hidden');
btn.classList.add('text-blue-500');
btn.classList.remove('text-slate-400');
} else {
input.type = 'password';
eye.classList.remove('hidden');
eyeOff.classList.add('hidden');
btn.classList.remove('text-blue-500');
btn.classList.add('text-slate-400');
}
}
</script>
@endsection
File diff suppressed because one or more lines are too long