🔧 refactor(laporan): kontrol akses role, optimasi query, dan perbaikan UI

- Tambah role `pemohon-ao` & `pemohon-eo` untuk upload lampiran di LampiranDokumen.php
- Implementasi kontrol akses role di lampiran-dokumen.blade.php & laporan/index.blade.php (logika khusus nilai_liquidasi)
- Modifikasi query di LaporanController.php: hapus filter approval_eo_at & optimasi kondisi WHERE
- Perbaikan formatting query dengan indentasi lebih rapi & maintainable
- Standardisasi urutan class CSS di beberapa Blade (activity/index, penilaian/otorisator/index-sla & index)
- Pisahkan logika generateLaporanButton jadi function terpisah di laporan/index.blade.php
- Perbaikan tampilan tombol laporan berbasis role + cleanup baris kosong & indentasi
- Konsistensi UI/UX: responsive design lebih baik, interface clean & styling konsisten dengan Tailwind
- Tingkatkan security & maintainability: granular role access, query lebih efisien, code lebih terstruktur
This commit is contained in:
Daeng Deni Mardaeni
2025-09-19 09:10:06 +07:00
parent ee7c8ce97f
commit 2b5556410d
9 changed files with 74 additions and 67 deletions

View File

@@ -75,7 +75,10 @@ class LaporanController extends Controller
}
// Retrieve data from the database
$query = Permohonan::query()->whereIn('status',['proses-laporan','done', 'paparan', 'proses-paparan'])->whereNotNull('approval_so_at')->whereNotNull('approval_eo_at')->where(function ($q) {
$query = Permohonan::query()->whereIn('status',['proses-laporan','done', 'paparan', 'proses-paparan'])
->whereNotNull('approval_so_at')
//->whereNotNull('approval_eo_at')
->where(function ($q) {
$q->whereIn('nilai_plafond_id', [1,4])
->whereNotNull('approval_dd_at')
->orWhereIn('nilai_plafond_id', [2,3]);

View File

@@ -27,7 +27,7 @@ class LampiranDokumen extends Base
{
$user = Auth::user();
if ($user && $user->hasAnyRole(['penilai', 'administrator', 'Penilai', 'admin','surveyor'])) {
if ($user && $user->hasAnyRole(['penilai', 'administrator', 'Penilai', 'admin','surveyor','pemohon-ao','pemohon-eo'])) {
$file = $fileData['file'];
$fileName = $fileData['nama_file'] ?? time() . '_' . $file->getClientOriginalName();
$filePath = $file->storeAs('lampiran_dokumen', $fileName, 'public');

View File

@@ -43,15 +43,15 @@
}
</style>
@endpush
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
<div class="card border border-agi-100 pb-2.5">
<div class="grid gap-5 mx-auto w-full lg:gap-7.5">
<div class="pb-2.5 border card border-agi-100">
<div class="card-header bg-agi-50" id="basic_settings">
<div class="card-title flex flex-row gap-1.5">
<div class="flex flex-row gap-1.5 card-title">
Activity
</div>
<div class="card-header bg-agi-50 py-5 flex-wrap">
<div class="flex-wrap py-5 card-header bg-agi-50">
<div class="flex flex-wrap gap-2 lg:gap-5">
<div class="flex">
@@ -64,30 +64,30 @@
<div class="dropdown" data-dropdown="true" data-dropdown-trigger="click">
<button
class="dropdowns-toggle btn btn-sm btn-light inline-flex justify-between w-full items-center">
class="inline-flex justify-between items-center w-full dropdowns-toggle btn btn-sm btn-light">
Pilih Status
<i class="ki-outline ki-down dropdown-open:hidden">
</i>
<i class="ki-outline ki-up hidden dropdown-open:block">
<i class="hidden ki-outline ki-up dropdown-open:block">
</i>
</button>
<div
class="dropdowns-content w-full max-w-56 py-2 absolute mt-2 origin-top-right z-50 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5">
<div class="menu menu-default flex flex-col w-full">
class="absolute z-50 py-2 mt-2 w-full bg-white rounded-md ring-1 ring-black ring-opacity-5 shadow-lg origin-top-right dropdowns-content max-w-56">
<div class="flex flex-col w-full menu menu-default">
<!-- Checkbox untuk All Status -->
<div class="menu-item">
<label class="menu-link flex items-center px-4 py-2 text-sm text-gray-700">
<label class="flex items-center px-4 py-2 text-sm text-gray-700 menu-link">
<input id="select-all" type="checkbox"
class="form-checkbox h-4 w-4 text-blue-600">
class="w-4 h-4 text-blue-600 form-checkbox">
<span class="ml-2">All Status</span>
</label>
</div>
<!-- Dinamis Status dari Backend -->
@foreach ($status_permohonan as $item)
<div class="menu-item">
<label class="menu-link flex items-center px-4 py-2 text-sm text-gray-700">
<label class="flex items-center px-4 py-2 text-sm text-gray-700 menu-link">
<input type="checkbox"
class="form-checkbox status-checkbox h-4 w-4 text-blue-600"
class="w-4 h-4 text-blue-600 form-checkbox status-checkbox"
value="{{ strtolower($item->name) }}">
<span class="ml-2">{{ $item->name }}</span>
</label>
@@ -105,12 +105,12 @@
</div>
</div>
<div class="card-grid min-w-full" data-datatable="false" data-datatable-page-size="10"
<div class="min-w-full card-grid" data-datatable="false" data-datatable-page-size="10"
data-datatable-state-save="false" id="permohonan-table" data-api-url="{{ route('activity.datatables') }}">
<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"
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border"
data-datatable-table="true">
<thead>
<tr>
@@ -158,13 +158,13 @@
</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">
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
<div class="flex gap-2 items-center">
Show
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select> per
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
page
</div>
<div class="flex items-center gap-4">
<div class="flex gap-4 items-center">
<span data-datatable-info="true"></span>
<div class="pagination" data-datatable-pagination="true"></div>
</div>
@@ -275,10 +275,10 @@
['survey', 'done', 'proses-laporan', 'laporan', 'paparan'].includes(status) ?
dokumenjaminan.map(dokumen => {
return `
<a class="btn btn-sm btn-icon btn-clear btn-info" href="surveyor/print-out-inspeksi/${data.id}/${dokumen.id}/${dokumen.jenis_jaminan_id}" title="Print Inspeksi Permohonan">
<i class="ki-outline ki-printer"></i>
</a>
`;
<a class="btn btn-sm btn-icon btn-clear btn-info" href="surveyor/print-out-inspeksi/${data.id}/${dokumen.id}/${dokumen.jenis_jaminan_id}" title="Print Inspeksi Permohonan">
<i class="ki-outline ki-printer"></i>
</a>
`;
}).join('') : ''
}
</div>
@@ -291,8 +291,6 @@
};
let dataTable = new KTDataTable(element, dataTableOptions);
function highlightFreezeRows() {

View File

@@ -37,7 +37,7 @@
@endforelse
</div>
@if(Auth::user()->hasRole(['Penilai', 'administrator','penilai','admin','surveyor']))
@if(Auth::user()->hasRole(['Penilai', 'administrator','penilai','admin','surveyor','pemohon-ao','pemohon-eo']))
<form action="{{ route('lampiran.upload') }}" method="POST" enctype="multipart/form-data" class="mt-6">
@csrf
<input type="hidden" name="permohonan_id" value="{{ $permohonan->id }}">

View File

@@ -246,27 +246,33 @@
</a>`;
}
if (data.nilai_liquidasi == null) {
laporanButton = `
@if (auth()->user()->hasRole('pemohon-ao'))
if (data.nilai_liquidasi == null) {
laporanButton = `
<a href="laporan/${data.id}" class="btn btn-sm btn-primary">
Laporan
</a>`;
}
if ((data.status_bayar == "sudah_bayar" || data.status_bayar == "tidak_bayar") && data
.nilai_liquidasi > 0) {
if (data.penilai.type_penilai == 'resume' && !data.penilai.resume) {
laporanButton = `
<a href="{{ route('penilai.print-out') }}?permohonanId=${data.id}&documentId=${dokumenID}&inspeksiId=${inspeksiId}&jaminanId=${jenisJaminanID}&statusLpj=0&type=${type}" class="btn btn-sm btn-primary">
Laporan
</a>`;
} else {
laporanButton = `
<a href="{{ route('penilai.print-out') }}?permohonanId=${data.id}&documentId=${dokumenID}&inspeksiId=${inspeksiId}&jaminanId=${jenisJaminanID}&statusLpj=0&type=${typePenilaian}" class="btn btn-sm btn-primary">
Laporan
</a>`;
}
@endif
@if (auth()->user()->hasRole('pemohon-ao'))
@if ((data.status_bayar == "sudah_bayar" || data.status_bayar == "tidak_bayar") && data.nilai_liquidasi > 0)
laporanButton = generateLaporanButton(data, dokumenID, inspeksiId, jenisJaminanID,
data.penilai.type_penilai == 'resume' && !data.penilai.resume ? type : typePenilaian);
@endif
@else
@if (data.status_bayar == "sudah_bayar" || data.status_bayar == "tidak_bayar")
laporanButton = generateLaporanButton(data, dokumenID, inspeksiId, jenisJaminanID,
data.penilai.type_penilai == 'resume' && !data.penilai.resume ? type : typePenilaian);
@endif
@endif
function generateLaporanButton(data, dokumenID, inspeksiId, jenisJaminanID, typeParam) {
return `
<a href="{{ route('penilai.print-out') }}?permohonanId=${data.id}&documentId=${dokumenID}&inspeksiId=${inspeksiId}&jaminanId=${jenisJaminanID}&statusLpj=0&type=${typeParam}" class="btn btn-sm btn-primary">
Laporan
</a>`;
}

View File

@@ -5,12 +5,12 @@
@endsection
@section('content')
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
<div class="card border border-agi-100 pb-2.5">
<div class=" card-grid min-w-full" data-datatable="false" data-datatable-page-size="10"
<div class="grid gap-5 mx-auto w-full lg:gap-7.5">
<div class="pb-2.5 border card border-agi-100">
<div class="min-w-full card-grid" data-datatable="false" data-datatable-page-size="10"
data-datatable-state-save="false" id="permohonan-table"
data-api-url="{{ route('otorisator.sla.datatables') }}">
<div class="card-header bg-agi-50 py-5 flex-wrap">
<div class="flex-wrap py-5 card-header bg-agi-50">
<h3 class="card-title">
Daftar {{ $header }}
</h3>
@@ -29,7 +29,7 @@
<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"
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border"
data-datatable-table="true">
<thead>
<tr>
@@ -81,13 +81,13 @@
</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">
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
<div class="flex gap-2 items-center">
Show
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select> per
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
page
</div>
<div class="flex items-center gap-4">
<div class="flex gap-4 items-center">
<span data-datatable-info="true"> </span>
<div class="pagination" data-datatable-pagination="true">
</div>

View File

@@ -5,8 +5,8 @@
@endsection
@section('content')
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
<div class="card border border-agi-100 card-grid min-w-full" data-datatable="false" data-datatable-page-size="10"
<div class="grid gap-5 mx-auto w-full lg:gap-7.5">
<div class="min-w-full border card border-agi-100 card-grid" data-datatable="false" data-datatable-page-size="10"
data-datatable-state-save="false" id="permohonan-table"
data-api-url="{{ route('otorisator.datatables', ['otorisator' => $header]) }}">
<div class="flex-wrap py-5 card-header bg-agi-50">
@@ -22,7 +22,7 @@
@if ($header == 'Pelaporan')
<div class="flex">
<select class="select select-sm w-28" id="region">
<select class="w-28 select select-sm" id="region">
<option value="">
Pilih Region
</option>
@@ -44,7 +44,7 @@
<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"
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border"
data-datatable-table="true">
<thead>
<tr>
@@ -112,13 +112,13 @@
</table>
</div>
<div
class="flex-col justify-center gap-3 font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
<div class="flex items-center gap-2">
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
<div class="flex gap-2 items-center">
Show
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
page
</div>
<div class="flex items-center gap-4">
<div class="flex gap-4 items-center">
<span data-datatable-info="true"> </span>
<div class="pagination" data-datatable-pagination="true">
</div>
@@ -234,7 +234,7 @@
title: 'Jenis laporan',
render: (item, data) => {
if (data.penilai.type_penilai) {
return `<span class="text-md font-bold capitalize">${data.penilai.type_penilai}</span>`;
return `<span class="font-bold capitalize text-md">${data.penilai.type_penilai}</span>`;
}
return '';
},
@@ -285,7 +285,7 @@
const isAdmin = userRoles.includes('administrator');
let buttons = `
<div class="flex justify-center flex-nowrap">
<div class="flex flex-nowrap justify-center">
<a class="btn btn-sm btn-icon btn-clear btn-warning" href="otorisator/show/${data.id}/${dataHeader}">
<i class="ki-outline ki-eye"></i>
</a>

View File

@@ -5,7 +5,7 @@
@endsection
@section('content')
<div class="w-full card grid gap-5 lg:gap-7.5 mx-auto">
<div class="grid gap-5 mx-auto w-full card lg:gap-7.5">
<div class="min-w-full card-grid" data-datatable="false" data-datatable-page-size="10"
data-datatable-state-save="false" id="permohonan-table"
@@ -98,13 +98,13 @@
</table>
</div>
<div
class="flex-col justify-center gap-3 font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
<div class="flex items-center gap-2">
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
<div class="flex gap-2 items-center">
Show
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
page
</div>
<div class="flex items-center gap-4">
<div class="flex gap-4 items-center">
<span data-datatable-info="true"> </span>
<div class="pagination" data-datatable-pagination="true">
</div>
@@ -280,7 +280,7 @@
const isAdmin = userRoles.includes('administrator');
let buttons = `
<div class="flex justify-center flex-nowrap">
<div class="flex flex-nowrap justify-center">
<a class="btn btn-sm btn-icon btn-clear btn-warning" href="otorisator/show/${data.id}/${dataHeader}">
<i class="ki-outline ki-eye"></i>
</a>

View File

@@ -167,7 +167,7 @@
<div class="flex items-stretch flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">Spek Bangunan</label>
<div class="flex flex-wrap items-baseline w-full" id="spek-bangunan-container">
@if (isset($forminspeksi['bangunan']) && is_array($forminspeksi['bangunan']))
@if (isset($forminspeksi['bangunan']) && is_array($forminspeksi['bangunan']) && !empty($forminspeksi['bangunan']['spesifikasi_bangunan']))
@foreach ($forminspeksi['bangunan']['spesifikasi_bangunan'] as $index => $bangunan)
<div class="spek-bangunan w-full gap-4 mt-5">
<input type="hidden" name="nama_bangunan[]"