MIF_E31232103/resources/views/super-admin/activity-logs/index.blade.php

333 lines
16 KiB
PHP

@extends('layouts.admin')
@section('title', 'Audit Log | Super Admin')
@section('page_title', 'Audit Log')
@push('styles')
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="{{ asset('assets/css/super-admin-audit-log.css') }}">
@endpush
@section('content')
@php
$logCollection = $activityLogs->getCollection();
$totalActivities = method_exists($activityLogs, 'total') ? (int) $activityLogs->total() : (int) $activityLogs->count();
$todayActivities = $logCollection->filter(function ($log) {
return $log->created_at && \Illuminate\Support\Carbon::parse($log->created_at)->isToday();
})->count();
$activeUsersInLogs = $logCollection->pluck('user_id')->filter()->unique()->count();
$actionGroups = $logCollection->countBy(function ($log) {
return strtolower((string) $log->action);
});
$topAction = $actionGroups->sortDesc()->keys()->first();
$targetGroups = $logCollection->countBy(function ($log) {
return strtolower((string) $log->target_type);
});
$topTargetType = $targetGroups->sortDesc()->keys()->first();
$targetTypeOptions = $logCollection
->pluck('target_type')
->filter()
->map(fn($value) => strtolower((string) $value))
->unique()
->values();
$actionBadge = function (?string $action): string {
$normalized = strtolower((string) $action);
return match (true) {
str_contains($normalized, 'create'), str_contains($normalized, 'store') => 'is-success',
str_contains($normalized, 'update'), str_contains($normalized, 'edit') => 'is-info',
str_contains($normalized, 'delete'), str_contains($normalized, 'destroy') => 'is-danger',
str_contains($normalized, 'verify'), str_contains($normalized, 'approve') => 'is-verify',
str_contains($normalized, 'reject'), str_contains($normalized, 'cancel') => 'is-warning',
str_contains($normalized, 'login'), str_contains($normalized, 'logout'), str_contains($normalized, 'system') => 'is-muted',
default => 'is-muted',
};
};
$targetBadge = function (?string $targetType): string {
$normalized = strtolower((string) $targetType);
return match ($normalized) {
'booking' => 'is-booking',
'payment' => 'is-payment',
'vehicle' => 'is-vehicle',
'rental', 'rental_company' => 'is-rental',
'promo' => 'is-promo',
'review' => 'is-review',
'user' => 'is-user',
default => 'is-system',
};
};
$prettyLabel = function (?string $raw): string {
$normalized = str_replace(['.', '_'], [' / ', ' '], strtolower((string) $raw));
return ucwords(trim($normalized) === '' ? '-' : trim($normalized));
};
@endphp
<div class="audit-page">
<div class="audit-breadcrumb">
<span>Super Admin</span>
<i class="bi bi-chevron-right" aria-hidden="true"></i>
<strong>Audit Log</strong>
</div>
<section class="audit-header-card">
<h2>Audit Log</h2>
<p>Pantau aktivitas penting sistem dan perubahan data yang dilakukan oleh pengguna platform.</p>
</section>
@if ($errors->any())
<section class="audit-inline-alert is-error" role="alert">
<i class="bi bi-exclamation-octagon" aria-hidden="true"></i>
<div>
<strong>Terjadi kesalahan saat filter data</strong>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
</section>
@endif
@if (session('success'))
<section class="audit-inline-alert is-success" role="status">
<i class="bi bi-check-circle" aria-hidden="true"></i>
<div>{{ session('success') }}</div>
</section>
@endif
@if (session('error'))
<section class="audit-inline-alert is-error" role="alert">
<i class="bi bi-x-circle" aria-hidden="true"></i>
<div>{{ session('error') }}</div>
</section>
@endif
@if (session('warning'))
<section class="audit-inline-alert is-warning" role="alert">
<i class="bi bi-exclamation-triangle" aria-hidden="true"></i>
<div>{{ session('warning') }}</div>
</section>
@endif
@if (session('info'))
<section class="audit-inline-alert is-info" role="status">
<i class="bi bi-info-circle" aria-hidden="true"></i>
<div>{{ session('info') }}</div>
</section>
@endif
<section class="audit-filter-card">
<form method="GET" action="{{ route('super-admin.activity-logs.index') }}" class="audit-filter-form">
<div class="audit-filter-group">
<label for="start_date">Start Date</label>
<input type="date" id="start_date" name="start_date" value="{{ request('start_date') }}">
</div>
<div class="audit-filter-group">
<label for="end_date">End Date</label>
<input type="date" id="end_date" name="end_date" value="{{ request('end_date') }}">
</div>
<div class="audit-filter-group">
<label for="user_id">User</label>
<select id="user_id" name="user_id">
<option value="">Semua User</option>
@foreach ($userOptions as $user)
<option value="{{ $user->id }}" @selected((string) request('user_id') === (string) $user->id)>
{{ $user->name }} ({{ $user->email }})
</option>
@endforeach
</select>
</div>
<div class="audit-filter-group">
<label for="action">Action</label>
<input type="text" id="action" name="action" value="{{ request('action') }}" placeholder="Contoh: booking.create">
</div>
<div class="audit-filter-group">
<label for="target_type">Target Type</label>
<select id="target_type" name="target_type">
<option value="">Semua Target</option>
@foreach ($targetTypeOptions as $option)
<option value="{{ $option }}" @selected((string) request('target_type') === (string) $option)>
{{ ucwords(str_replace('_', ' ', $option)) }}
</option>
@endforeach
</select>
</div>
<div class="audit-filter-actions">
<button type="submit" class="audit-btn-primary">
<i class="bi bi-funnel-fill" aria-hidden="true"></i>
<span>Terapkan Filter</span>
</button>
<a href="{{ route('super-admin.activity-logs.index') }}" class="audit-btn-secondary">
<i class="bi bi-arrow-counterclockwise" aria-hidden="true"></i>
<span>Reset Filter</span>
</a>
</div>
</form>
</section>
<section class="audit-stat-grid">
<article class="audit-stat-card">
<div class="audit-stat-icon"><i class="bi bi-list-check" aria-hidden="true"></i></div>
<div>
<p>Total Aktivitas</p>
<h3>{{ number_format($totalActivities, 0, ',', '.') }}</h3>
</div>
</article>
<article class="audit-stat-card">
<div class="audit-stat-icon"><i class="bi bi-calendar-event" aria-hidden="true"></i></div>
<div>
<p>Aktivitas Hari Ini</p>
<h3>{{ number_format($todayActivities, 0, ',', '.') }}</h3>
<small>berdasarkan halaman ini</small>
</div>
</article>
<article class="audit-stat-card">
<div class="audit-stat-icon"><i class="bi bi-people" aria-hidden="true"></i></div>
<div>
<p>Total User Aktif di Log</p>
<h3>{{ number_format($activeUsersInLogs, 0, ',', '.') }}</h3>
<small>berdasarkan halaman ini</small>
</div>
</article>
<article class="audit-stat-card">
<div class="audit-stat-icon"><i class="bi bi-bar-chart" aria-hidden="true"></i></div>
<div>
<p>Action / Target Terbanyak</p>
<h3>{{ $prettyLabel($topAction) }}</h3>
<small>{{ $prettyLabel($topTargetType) }}</small>
</div>
</article>
</section>
<section class="audit-actions-row">
<a href="{{ route('super-admin.reports.index') }}" class="audit-mini-link">
<i class="bi bi-graph-up-arrow" aria-hidden="true"></i>
<span>Buka Laporan Super Admin</span>
</a>
<a href="{{ route('super-admin.dashboard') }}" class="audit-mini-link">
<i class="bi bi-speedometer2" aria-hidden="true"></i>
<span>Kembali ke Dashboard</span>
</a>
</section>
<section class="audit-table-card">
<div class="audit-table-head">
<h3>Data Audit Log</h3>
<p>Log terbaru ditampilkan di atas untuk membantu investigasi aktivitas sistem.</p>
</div>
@if ($activityLogs->count() > 0)
<div class="audit-table-wrap">
<table class="audit-table">
<thead>
<tr>
<th class="is-center">No</th>
<th>Waktu</th>
<th>User</th>
<th>Action</th>
<th>Target Type</th>
<th class="is-center">Target ID</th>
<th>Deskripsi</th>
<th>Meta / Detail Singkat</th>
<th class="is-center">Aksi</th>
</tr>
</thead>
<tbody>
@foreach ($activityLogs as $index => $log)
@php
$createdAt = $log->created_at ? \Illuminate\Support\Carbon::parse($log->created_at) : null;
$metaSummary = '-';
if (is_array($log->meta) && count($log->meta) > 0) {
$pairs = collect($log->meta)
->take(3)
->map(function ($value, $key) {
$keyText = str_replace('_', ' ', (string) $key);
$valueText = is_scalar($value) ? (string) $value : json_encode($value);
return $keyText . ': ' . $valueText;
})
->values();
$metaSummary = $pairs->implode(' | ');
}
@endphp
<tr>
<td class="is-center">{{ ($activityLogs->firstItem() ?? 1) + $index }}</td>
<td>
<strong>{{ $createdAt?->format('d M Y') ?? '-' }}</strong>
<br>
<small>{{ $createdAt?->format('H:i:s') ?? '-' }}</small>
</td>
<td>
@if ($log->user)
<strong>{{ $log->user->name }}</strong>
<br>
<small>{{ $log->user->email }}</small>
@else
<strong>System</strong>
<br>
<small>Unknown User</small>
@endif
</td>
<td>
<span class="audit-badge {{ $actionBadge($log->action) }}">
{{ $prettyLabel($log->action) }}
</span>
</td>
<td>
<span class="audit-badge {{ $targetBadge($log->target_type) }}">
{{ $prettyLabel($log->target_type) }}
</span>
</td>
<td class="is-center">{{ $log->target_id ?? '-' }}</td>
<td>
<div class="line-clamp-2" title="{{ $log->description ?? '-' }}">{{ $log->description ?? '-' }}</div>
</td>
<td>
<div class="line-clamp-2" title="{{ $metaSummary }}">{{ $metaSummary }}</div>
</td>
<td class="is-center">
@if (Route::has('super-admin.activity-logs.show'))
<a href="{{ route('super-admin.activity-logs.show', $log) }}" class="audit-action-btn">
<i class="bi bi-box-arrow-up-right" aria-hidden="true"></i>
<span>Detail</span>
</a>
@else
<span class="audit-action-btn is-disabled">
<i class="bi bi-lock" aria-hidden="true"></i>
<span>Detail</span>
</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="audit-pagination-wrap">
{{ $activityLogs->links() }}
</div>
@else
<div class="audit-empty-state">
<i class="bi bi-inbox" aria-hidden="true"></i>
<h4>Belum ada data audit log</h4>
<p>Aktivitas sistem akan muncul di halaman ini saat pengguna mulai melakukan aksi pada platform.</p>
</div>
@endif
</section>
</div>
@endsection