FEAT : Update Dashboard DONE

This commit is contained in:
Ramanda Syahputra 2025-05-02 16:41:13 +07:00
parent c1b1a00c90
commit a8bd400753
4 changed files with 186 additions and 125 deletions

View File

@ -1,22 +1,35 @@
<?php <?php
use Carbon\Carbon;
if(!function_exists('formatTanggalWaktu')){ use Carbon\Carbon;
function formatTanggalWaktu($tanggal, $time=false, $showDay=false, $locale = 'id_ID')
{
// Parse tanggal dan waktu
$datetime = $time ? $tanggal . ' ' . $time : $tanggal;
$carbon = Carbon::parse($datetime)->locale($locale);
// Tentukan format berdasarkan parameter if (!function_exists('formatTanggalWaktu')) {
if ($showDay && $time) { function formatTanggalWaktu($tanggal, $time = false, $showDay = false, $locale = 'id_ID')
return $carbon->isoFormat('dddd, LL HH:mm:ss'); {
} elseif ($showDay) { // Parse tanggal dan waktu
return $carbon->isoFormat('dddd, LL'); $datetime = $time ? $tanggal . ' ' . $time : $tanggal;
} elseif ($time) { $carbon = Carbon::parse($datetime)->locale($locale);
return $carbon->isoFormat('LL HH:mm:ss');
} else { // Tentukan format berdasarkan parameter
return $carbon->isoFormat('LL'); if ($showDay && $time) {
} return $carbon->isoFormat('dddd, LL HH:mm:ss');
} elseif ($showDay) {
return $carbon->isoFormat('dddd, LL');
} elseif ($time) {
return $carbon->isoFormat('LL HH:mm:ss');
} else {
return $carbon->isoFormat('LL');
} }
} }
}
function formatNotifikasi($notifikasi)
{
$data = json_decode(json_encode($notifikasi->data));
$message = $data->message;
$data = $data->data;
$notifikasi = [
'title' => $message->title,
'message' => $message->message,
];
return $notifikasi;
}

View File

@ -15,12 +15,13 @@
"intervention/image": "^3.10", "intervention/image": "^3.10",
"joshbrw/laravel-module-installer": "^2.0", "joshbrw/laravel-module-installer": "^2.0",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"jackiedo/log-reader": "^2.4",
"laravel/pulse": "^1.2", "laravel/pulse": "^1.2",
"laravel/tinker": "^2.9", "laravel/tinker": "^2.9",
"maatwebsite/excel": "^3.1", "maatwebsite/excel": "^3.1",
"nwidart/laravel-modules": "^11.0", "nwidart/laravel-modules": "^11.0",
"opcodesio/log-viewer": "^3.10", "opcodesio/log-viewer": "^3.10",
"rasyahroel/itsecurity": "dev-main", "rasyahroel/itsecurity-module": "dev-main",
"rasyahroel/usermanagement-module": "dev-master", "rasyahroel/usermanagement-module": "dev-master",
"spatie/laravel-activitylog": "^4.8", "spatie/laravel-activitylog": "^4.8",
"spatie/laravel-pdf": "^1.5", "spatie/laravel-pdf": "^1.5",
@ -41,7 +42,10 @@
"App\\": "app/", "App\\": "app/",
"Database\\Factories\\": "database/factories/", "Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/" "Database\\Seeders\\": "database/seeders/"
} },
"files": [
"app/Helpers/helpers.php"
]
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
@ -106,9 +110,14 @@
"url": "https://git.putrakuningan.com/daengdeni/authentication" "url": "https://git.putrakuningan.com/daengdeni/authentication"
}, },
{ {
"name": "rasyahroel/itsecurity", "name": "rasyahroel/itsecurity-module",
"type": "vcs", "type": "vcs",
"url": "https://git.putrakuningan.com/rasyahroel/itsecurity" "url": "https://git.putrakuningan.com/rasyahroel/itsecurity"
},
{
"name": "jackiedo/log-reader",
"type": "vcs",
"url": "https://github.com/daengdeni/Laravel-Log-Reader.git"
} }
] ]
} }

View File

@ -50,75 +50,17 @@
</div> </div>
</div> </div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-5 lg:gap-7.5 items-stretch"> {{-- Report History User --}}
{{-- Report History User --}} <div class="grid my-5 gap-5 lg:gap-7.5">
<div class="grid my-5 gap-5 lg:gap-7.5"> <div class="card border border-agi-100 card-grid min-w-full" data-datatable="false" data-datatable-page-size="5"
<div class="card border border-agi-100 card-grid min-w-full" data-datatable="false" data-datatable-state-save="false" id="dashboardreport-table"
data-datatable-page-size="5" data-datatable-state-save="false" id="dashboardreport-table" data-api-url="{{ route('report.laporanhistory.datatables') }}">
data-api-url="{{ route('report.laporanhistory.datatables') }}"> <div class="card-header bg-agi-50 py-5 flex-wrap">
<div class="card-header bg-agi-50 py-5 flex-wrap"> <h3 class="card-title">
<h3 class="card-title"> Report History User Akses
Report History User Akses </h3>
</h3>
</div>
<div class="card-body">
<div class="scrollable-x-auto">
<table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm"
data-datatable-table="true">
<thead>
<tr>
<th class="min-w-[100px]" data-datatable-column="nik">
<span class="sort"> <span class="sort-label"> NIK </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="name">
<span class="sort"> <span class="sort-label"> Nama User </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="unit">
<span class="sort"> <span class="sort-label"> Unit </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="jenis_form">
<span class="sort"> <span class="sort-label"> Akses Yang Di Miliki </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="jangka_waktu">
<span class="sort"> <span class="sort-label"> Periode </span>
<span class="sort-icon"> </span> </span>
</th>
</tr>
</thead>
</table>
</div>
<div
class="card-footer justify-center md:justify-between flex-col md:flex-row gap-3 text-gray-600 text-2sm font-medium">
<div class="flex items-center gap-2">
Show
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select>
per
page
</div>
<div class="flex items-center gap-4">
<span data-datatable-info="true"> </span>
<div class="pagination" data-datatable-pagination="true">
</div>
</div>
</div>
</div>
</div> </div>
</div> <div class="card-body">
{{-- Audit Rail --}}
<div class="grid my-5 gap-5 lg:gap-7.5">
<div class="card border border-agi-100 card-grid min-w-full" data-datatable="false"
data-datatable-page-size="5" data-datatable-state-save="false" id="audit-table"
data-api-url="{{ route('auditrail.datatables') }}">
<div class="card-header bg-agi-50 py-5 flex-wrap">
<h3 class="card-title">
Audit Trail
</h3>
</div>
<div class="scrollable-x-auto"> <div class="scrollable-x-auto">
<table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm" <table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm"
data-datatable-table="true"> data-datatable-table="true">
@ -129,23 +71,19 @@
<span class="sort-icon"> </span> </span> <span class="sort-icon"> </span> </span>
</th> </th>
<th class="min-w-[100px]" data-datatable-column="name"> <th class="min-w-[100px]" data-datatable-column="name">
<span class="sort"> <span class="sort-label"> Name </span> <span class="sort"> <span class="sort-label"> Nama User </span>
<span class="sort-icon"> </span> </span> <span class="sort-icon"> </span> </span>
</th> </th>
<th class="min-w-[100px]" data-datatable-column="action_type"> <th class="min-w-[100px]" data-datatable-column="unit">
<span class="sort"> <span class="sort-label"> Action Type </span> <span class="sort"> <span class="sort-label"> Unit </span>
<span class="sort-icon"> </span> </span> <span class="sort-icon"> </span> </span>
</th> </th>
<th class="min-w-[100px]" data-datatable-column="action_description"> <th class="min-w-[100px]" data-datatable-column="jenis_form">
<span class="sort"> <span class="sort-label"> Action Description</span> <span class="sort"> <span class="sort-label"> Akses Yang Di Miliki </span>
<span class="sort-icon"> </span> </span> <span class="sort-icon"> </span> </span>
</th> </th>
<th class="min-w-[100px]" data-datatable-column="target_table"> <th class="min-w-[100px]" data-datatable-column="jangka_waktu">
<span class="sort"> <span class="sort-label"> Target Table </span> <span class="sort"> <span class="sort-label"> Periode </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="target_record_id">
<span class="sort"> <span class="sort-label"> Target Record Id </span>
<span class="sort-icon"> </span> </span> <span class="sort-icon"> </span> </span>
</th> </th>
</tr> </tr>
@ -169,6 +107,98 @@
</div> </div>
</div> </div>
</div> </div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-5 lg:gap-7.5 items-stretch">
{{-- History User --}}
<div class="grid my-5 gap-5 lg:gap-7.5">
<div class="card border border-agi-100 card-grid min-w-full" id="dashboardhistory">
<div class="card-header bg-agi-50 py-5 flex-wrap">
<h3 class="card-title">
History User Akses
</h3>
</div>
<div class="card-body">
@foreach (auth()->user()->unreadNotifications->take(5) as $notification)
<div class="flex items-center grow gap-2.5 px-5 py-4">
<div
class="flex items-center justify-center size-8 bg-success-light rounded-full border border-success-clarity">
<i class="ki-filled ki-check text-lg text-success">
</i>
</div>
<div class="flex flex-col gap-1">
<span class="text-2sm font-medium text-gray-700">
{{ formatNotifikasi($notification)['title'] }}<br>
{{ formatNotifikasi($notification)['message'] }}<br>
</span>
<span class="font-medium text-gray-500 text-2xs">
{{ $notification->created_at->diffForHumans() }}
</span>
</div>
</div>
@if (!$loop->last)
<div class="border-b border-b-gray-200"></div>
@endif
@endforeach
</div>
</div>
</div>
{{-- Audit Rail --}}
<div class="grid my-5 gap-5 lg:gap-7.5">
<div class="card border-agi-100 card-grid min-w-full" data-datatable="false" data-datatable-page-size="5"
data-datatable-state-save="false" id="audit-logs-table"
data-api-url="{{ route('logs.audit.datatables') }}">
<div class="card-header bg-agi-50 py-5 flex-wrap">
<h3 class="card-title">
Audit Logs
</h3>
</div>
<div class="scrollable-x-auto">
<table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm"
data-datatable-table="true">
<thead>
<tr>
<th class="min-w-[100px]" data-datatable-column="log_name">
<span class="sort"> <span class="sort-label"> Log Type </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="subject_type">
<span class="sort"> <span class="sort-label"> Subject Type </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="description">
<span class="sort"> <span class="sort-label"> Description </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[100px]" data-datatable-column="causer_id">
<span class="sort"> <span class="sort-label"> Causer ID </span>
<span class="sort-icon"> </span> </span>
</th>
<th class="min-w-[150px]" data-datatable-column="created_at">
<span class="sort"> <span class="sort-label"> Date/Time </span>
<span class="sort-icon"> </span> </span>
</th>
</tr>
</thead>
</table>
</div>
<div
class="card-footer justify-center md:justify-between flex-col md:flex-row gap-3 text-gray-600 text-2sm font-medium">
<div class="flex items-center gap-2">
Show
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select>
per page
</div>
<div class="flex items-center gap-4">
<span data-datatable-info="true"> </span>
<div class="pagination" data-datatable-pagination="true">
</div>
</div>
</div>
</div>
</div>
</div>
</div> </div>
@endsection @endsection
@ -182,7 +212,7 @@
const ctx = document.getElementById('dashboardChart').getContext('2d'); const ctx = document.getElementById('dashboardChart').getContext('2d');
new Chart(ctx, { new Chart(ctx, {
type: 'pie', // tipe chart type: 'pie',
data: { data: {
labels: labels, labels: labels,
datasets: [{ datasets: [{
@ -276,34 +306,43 @@
}; };
const datatableReport = new KTDataTable(elementReport, dataTableReportOptions); const datatableReport = new KTDataTable(elementReport, dataTableReportOptions);
const elementAudit = document.querySelector('#audit-table'); const elementAudit = document.querySelector('#audit-logs-table');
const apiUrlAudit = elementAudit.getAttribute('data-api-url'); const apiUrlAudit = elementAudit.getAttribute('data-api-url');
// Inisialisasi DataTable // Inisialisasi DataTable Audit
const dataTableAuditOptions = { const dataTableAuditOptions = {
apiEndpoint: apiUrlAudit, apiEndpoint: apiUrlAudit,
pageSize: 5, pageSize: 5,
columns: { columns: {
nik: { log_name: {
title: 'nik', title: 'Log Type',
render: (item, data) => data?.user?.nik || 'Unknown', render: (item, data) => {
return `<span class="badge badge-light-primary">${data.log_name || 'N/A'}</span>`;
}
}, },
name: { description: {
title: 'name', title: 'Description',
render: (item, data) => data?.user?.name || 'Unknown',
}, },
action_type: { subject_type: {
title: 'action_type', title: 'Subject Type',
render: (item, data) => {
if (!data.subject_type) return 'N/A';
return data.subject_type.split('\\').pop();
}
}, },
action_description: { causer_id: {
title: 'action_description', title: 'Causer ID',
}, render: (item, data) => {
target_table: { return data.creator_name || 'System';
title: 'target_table', }
},
target_record_id: {
title: 'target_record_id',
}, },
created_at: {
title: 'Date/Time',
render: (item, data) => {
const date = new Date(data.created_at);
return window.formatTanggalWaktuIndonesia(date)
}
}
}, },
}; };
const datatableAudit = new KTDataTable(elementAudit, dataTableAuditOptions); const datatableAudit = new KTDataTable(elementAudit, dataTableAuditOptions);

View File

@ -1,15 +1,15 @@
<?php <?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\DashboardController; use App\Http\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('/notifications/count', function () {
return response()->json([
'count' => auth()->user()->unreadNotifications->count()
]);
})->name('notifications.count')->middleware('auth');
});
Route::middleware(['auth'])->group(function () { Route::middleware(['auth'])->group(function () {
Route::get('/notifications/count', function () {
return response()->json([
'count' => auth()->user()->unreadNotifications->count()
]);
})->name('notifications.count')->middleware('auth');
Route::get('/', [DashboardController::class, 'index'])->name('dashboard'); Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
}); });