progress action approval

This commit is contained in:
JokoPrasetio 2026-01-23 16:15:16 +07:00
parent 44c4689f77
commit 093a8f2b4d
21 changed files with 1088 additions and 118 deletions

View File

@ -3,9 +3,9 @@
namespace App\Http\Controllers;
use App\Models\AksesFile;
use App\Models\AksesFileDetail;
use App\Models\DataUser;
use App\Models\FileDirectory;
use App\Models\MappingUnitKerjaPegawai;
use App\Models\UnitKerja;
use Carbon\Carbon;
use Illuminate\Http\Request;
@ -41,21 +41,25 @@ class AksesFileController extends Controller
try {
$datas = request('data');
foreach ($datas as $data) {
$pegawai = MappingUnitKerjaPegawai::where(['objectpegawaifk'=> $data['pegawai_id'], 'statusenabled' => true])->first();
$payload = [
'pegawai_id' => $data['pegawai_id'],
'pegawai_id_entry' => auth()->user()?->dataUser?->id,
'pegawai_nama_entry' => auth()->user()?->dataUser?->namalengkap,
'entry_at' => Carbon::now()->format('Y-m-d H:i:s.u'),
'all_akses' => $data['akses'] === "all" ? true : false,
];
if($data['akses'] === "all"){
$payload['all_akses'] = true;
}else{
$payload['all_akses'] = false;
$payload['unit_akses'] = $pegawai->objectunitkerjapegawaifk ?? null;
$af = AksesFile::create($payload);
if($data['akses'] === "unit"){
$unitIds = collect($data['unit_akses'] ?? [])->filter()->unique()->values();
foreach ($unitIds as $unitId) {
$payloadDetail = [
'akses_file_id' => $af->akses_file_id,
'statusenabled' => true,
'id_unit_kerja' => $unitId,
];
AksesFileDetail::create($payloadDetail);
}
}
AksesFile::create($payload);
}
DB::connection('dbDirectory')->commit();
return response()->json([
@ -76,7 +80,55 @@ class AksesFileController extends Controller
*/
public function show(string $id)
{
//
$data = AksesFile::where('akses_file_id', $id)->first();
if (!$data) {
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
}
$aksesAll = $data->akses ?? null;
if (is_null($aksesAll)) {
$aksesAll = $data->all_akses ?? null;
}
$aksesType = $aksesAll ? 'all' : 'unit';
$units = [];
$detailUnits = AksesFileDetail::where('akses_file_id', $id)
->where('statusenabled', true)
->get();
if ($detailUnits->isNotEmpty()) {
$unitIds = $detailUnits->pluck('id_unit_kerja');
$units = UnitKerja::whereIn('id', $unitIds)
->select('id', 'name')
->get()
->map(function ($unit) {
return [
'id' => $unit->id,
'text' => $unit->name,
];
})
->values();
} elseif (!empty($data->unit_akses)) {
$unit = UnitKerja::where('id', $data->unit_akses)->select('id', 'name')->first();
if ($unit) {
$units[] = [
'id' => $unit->id,
'text' => $unit->name,
];
}
}
return response()->json([
'status' => true,
'data' => [
'akses_type' => $aksesType,
'pegawai_id' => $data->pegawai_id,
'pegawai_nama' => $data?->pegawai?->namalengkap,
'units' => $units,
]
], 200);
}
/**
@ -92,19 +144,40 @@ class AksesFileController extends Controller
*/
public function update(Request $request, string $id)
{
DB::connection('dbDirectory')->beginTransaction();
try {
$data = AksesFile::where('akses_file_id', $id)->first();
$pegawai = MappingUnitKerjaPegawai::where(['objectpegawaifk' => request('pegawai_id'), 'statusenabled' => true])->first();
if (!$data) {
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
}
$payload = [
'pegawai_id' => request('pegawai_id'),
'pegawai_id_modified' => auth()->user()?->dataUser?->id,
'pegawai_nama_modified' => auth()->user()?->dataUser?->namalengkap,
'modified_at' => Carbon::now()->format('Y-m-d H:i:s.u'),
'all_akses' => request('akses') === "all" ? true : false,
'unit_akses' => $pegawai?->objectunitkerjapegawaifk ?? null
];
$data->update($payload);
AksesFileDetail::where('akses_file_id', $id)->delete();
if (request('akses') === 'unit') {
$unitIds = collect(request('unit_akses') ?? [])->filter()->unique()->values();
foreach ($unitIds as $unitId) {
$payloadDetail = [
'akses_file_id' => $data->akses_file_id,
'statusenabled' => true,
'id_unit_kerja' => $unitId,
];
AksesFileDetail::create($payloadDetail);
}
}
DB::connection('dbDirectory')->commit();
return response()->json([
'status' => true,
'message' => 'Data berhasil diperbarui',
@ -123,26 +196,43 @@ class AksesFileController extends Controller
*/
public function destroy(string $id)
{
$data = AksesFile::where('akses_file_id', $id)->first();
if(!$data){
try {
$data = AksesFile::where('akses_file_id', $id)
->where('statusenabled', true)
->first();
if (!$data) {
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
}
DB::transaction(function () use ($id, $data) {
AksesFileDetail::where('akses_file_id', $id)
->where('statusenabled', true)
->update(['statusenabled' => false]);
$data->update(['statusenabled' => false]);
});
return response()->json([
'status' => true,
'message' => 'Data berhasil dihapus'
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
'message' => 'Gagal menghapus data',
], 500);
}
$payload =[
'statusenabled' => false
];
$data->update($payload);
return response()->json([
'status' => true,
'message' => 'Data berhasil dihapus'
], 200);
}
public function datatable(){
return AksesFile::where('statusenabled', true)->get();
return AksesFile::with(['details.unit'])
->where('statusenabled', true)
->get();
}
public function optionPegawai(){

View File

@ -3,12 +3,14 @@
namespace App\Http\Controllers;
use App\Models\AksesFile;
use App\Models\AksesFileDetail;
use App\Models\FileDirectory;
use App\Models\LogActivity;
use App\Models\MasterKategori;
use App\Models\MasterKlasifikasi;
use App\Models\SubUnitKerja;
use App\Models\UnitKerja;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
@ -43,19 +45,37 @@ class DashboardController extends Controller
public function dataUnitKerja(){
$user = auth()->user()?->dataUser;
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
$aksesAll = $akses?->akses ?? $akses?->all_akses ?? false;
$detailUnitIds = collect();
if ($akses?->akses_file_id) {
$detailUnitIds = AksesFileDetail::where('akses_file_id', $akses->akses_file_id)
->where('statusenabled', true)
->pluck('id_unit_kerja')
->unique()
->values();
}
$allowedUnitIds = null;
if (!$aksesAll) {
if ($detailUnitIds->isNotEmpty()) {
$allowedUnitIds = $detailUnitIds;
} elseif (!empty($akses?->unit_akses)) {
$allowedUnitIds = collect([$akses->unit_akses]);
}
}
$kategori = request('kategori');
$filterUnit = request('unitKerja');
$subUnit = request('subUnit');
$klasifikasi = request('klasifikasi');
$keyword = request('keyword');
$subArray = $subUnit ? explode(',', $subUnit) : [];
$katArray = $kategori ? explode(',', $kategori) : [];
$klaArray = $klasifikasi ? explode(',', $klasifikasi) : [];
$katDok = MasterKategori::when($katArray, fn($q) => $q->whereIn('master_kategori_directory_id', $katArray))->where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
if ($katArray && $filterUnit && $subArray && $klaArray) {
if ($katArray && $filterUnit && $subArray) {
/* mode pencarian lengkap */
if ($allowedUnitIds && !$allowedUnitIds->contains((int) $filterUnit)) {
$unitKerja = collect();
} else {
$unitKerja = UnitKerja::where('statusenabled', true)
->where('id', $filterUnit)
->with(['subUnitKerja' => fn($q) => $q->whereIn('id', $subArray)
@ -63,7 +83,6 @@ class DashboardController extends Controller
->where('id_unit_kerja', $filterUnit)
->when($subArray, fn($q) => $q->whereIn('id_sub_unit_kerja', $subArray))
->when($katArray, fn($q) => $q->whereIn('master_kategori_directory_id', $katArray))
->when($klaArray, fn($q) => $q->whereIn('master_klasifikasi_directory_id', $klaArray))
->when($keyword, fn($q) =>
$q->where(function($query) use ($keyword) {
$query->where('file', 'ilike', "%{$keyword}%")
@ -74,8 +93,9 @@ class DashboardController extends Controller
])
->select('id', 'name')
->get();
}
} elseif ($akses?->all_akses) {
} elseif ($aksesAll) {
/* all akses */
$unitKerja = UnitKerja::where('statusenabled', true)->with([ // muat relasi
'subUnitKerja' => fn($q) => $q->with([ // sub-unit
@ -88,9 +108,10 @@ class DashboardController extends Controller
->select('id', 'name')
->get();
} elseif ($akses?->unit_akses) {
/* akses per unit */
$unitKerja = UnitKerja::where(['statusenabled' => true, 'id' => $akses->unit_akses])
} elseif ($allowedUnitIds) {
/* akses per unit (single/multiple) */
$unitKerja = UnitKerja::where('statusenabled', true)
->whereIn('id', $allowedUnitIds)
->with([ // muat relasi
'subUnitKerja' => fn($q) => $q->with([ // sub-unit
'fileDirectory' => fn($f) => $f->when($keyword, fn($q) =>
@ -378,23 +399,43 @@ class DashboardController extends Controller
public function dataDocumentLast(){
$perPage = (int) request('per_page', 10);
$authUnitId = auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->objectunitkerjapegawaifk;
$user = auth()->user()?->dataUser;
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
$keyword = request('keyword');
$data = FileDirectory::where('statusenabled', true)
->where(function ($query) use ($authUnitId) {
$query->where('permission_file', true)
->orWhere(function ($sub) use ($authUnitId) {
$sub->where('permission_file', false)
->where('id_unit_kerja', $authUnitId);
});
})
$query = FileDirectory::where('statusenabled', true)
->when($keyword, function ($q) use ($keyword) {
$q->where(function ($sub) use ($keyword) {
$sub->where('file', 'ILIKE', "%{$keyword}%")
->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%");
});
})
->orderBy('entry_at', 'desc')
});
if($akses){
if(!$akses->all_akses){
$aksesFile = AksesFileDetail::where('akses_file_id', $akses->akses_file_id)->pluck('id_unit_kerja');
$query->where(function ($query) use ($authUnitId, $aksesFile) {
$query->where('permission_file', true)
->orWhere(function ($sub) use ($authUnitId, $aksesFile) {
$sub->where('permission_file', false)
->whereIn('id_unit_kerja', $aksesFile);
});
});
}else{
$query;
}
}else{
$query->where(function ($query) use ($authUnitId) {
$query->where('permission_file', true)
->orWhere(function ($sub) use ($authUnitId) {
$sub->where('permission_file', false)
->where('id_unit_kerja', $authUnitId);
});
});
}
$data = $query->orderBy('entry_at', 'desc')
->paginate($perPage);
$payload = [
@ -661,8 +702,10 @@ class DashboardController extends Controller
foreach ($grouped as $unitName => $folders) {
$data = [];
foreach ($folders as $folder => $count) {
$sliceText = array_values(array_filter(explode('/', $folder)));
$data[] = [
'folder'=> $folder,
'subUnit' => $sliceText[0],
'folder'=> $sliceText[1],
'count' => $count,
];
}
@ -701,4 +744,161 @@ class DashboardController extends Controller
public function recapView(){
return view('dashboard.recap', ['title' => 'Rekap Dokumen']);
}
public function pendingFile(){
return view('pendingFile.index', ['title' => 'Data Pending']);
}
public function dataPendingFile(){
$perPage = (int) request('per_page', 10);
$keyword = request('keyword');
$start = request('start_date');
$end = request('end_date');
$query = FileDirectory::where('statusenabled', true)->whereNull('status_action')->orderBy('entry_at','desc');
if($keyword){
$query->where(function($q) use ($keyword){
$q->where('file', 'ILIKE', "%{$keyword}%")
->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%");
});
}
if($start){
$query->whereDate('entry_at','>=',$start);
}
if($end){
$query->whereDate('entry_at','<=',$end);
}
$paginated = $query->paginate($perPage);
$data = $paginated->getCollection()->map(function($item){
$dataSlice = array_values(array_filter(explode('/', $item->file)));
return [
'file_directory_id' => $item->file_directory_id,
'pegawai_nama_entry' => $item->pegawai_nama_entry,
'part' => $dataSlice[0] . '/' . $dataSlice[1],
'folder' => $dataSlice[2],
'fileName' =>$dataSlice[3],
'file' => $item->file,
'no_dokumen' => $item->no_dokumen,
'entry_at' => $item->entry_at,
'tanggal_terbit' => $item->tanggal_terbit,
'permission_file' => $item->permission_file,
];
});
return response()->json([
'status' => true,
'data' => $data,
'pagination' => [
'current_page' => $paginated->currentPage(),
'next_page' => $paginated->hasMorePages() ? $paginated->currentPage() + 1 : null,
'has_more' => $paginated->hasMorePages(),
'last_page' => $paginated->lastPage(),
'per_page' => $paginated->perPage(),
'total' => $paginated->total(),
]
]);
}
public function approvePendingFile(string $id){
try {
$data = FileDirectory::where('file_directory_id', $id)->first();
if(!$data){
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
}
$data->update([
'status_action' => 'approved',
'action_at' => Carbon::now(),
'action_by' => auth()->user()->dataUser->id,
]);
$payloadLog = [
'file_directory_id' => $data->file_directory_id,
'pegawai_id_entry' => $data->action_by,
'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap,
'entry_at' => $data->action_at,
'action_type' => 'Approval Dokumen',
'statusenabled' => true,
'mod_change' => $data->entry_at,
'id_unit_kerja' => $data->id_unit_kerja,
'id_sub_unit_kerja' => $data->id_sub_unit_kerja,
'file' => $data->file,
'tanggal_terbit' => $data->tanggal_terbit,
'no_dokumen' => $data->no_dokumen,
'permission_file' => $data->permission_file,
];
LogActivity::create($payloadLog);
return response()->json([
'status' => true,
'message' => 'File berhasil di-approve'
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
public function rejectPendingFile(string $id){
try {
$data = FileDirectory::where('file_directory_id', $id)->first();
if(!$data){
return response()->json([
'status' => false,
'message' => 'Data tidak ditemukan'
], 404);
}
$data->update([
'status_action' => 'rejected',
'action_at' => Carbon::now(),
'action_by' => auth()->user()->dataUser->id,
]);
$payloadLog = [
'file_directory_id' => $data->file_directory_id,
'pegawai_id_entry' => $data->action_by,
'pegawai_nama_entry' => auth()->user()->dataUser->namalengkap,
'entry_at' => $data->action_at,
'action_type' => 'Reject Dokumen',
'statusenabled' => true,
'mod_change' => $data->entry_at,
'id_unit_kerja' => $data->id_unit_kerja,
'id_sub_unit_kerja' => $data->id_sub_unit_kerja,
'file' => $data->file,
'tanggal_terbit' => $data->tanggal_terbit,
'no_dokumen' => $data->no_dokumen,
'permission_file' => $data->permission_file,
];
LogActivity::create($payloadLog);
return response()->json([
'status' => true,
'message' => 'File berhasil di-reject'
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => $th->getMessage()
], 500);
}
}
public function countDataPending(){
try {
$count = FileDirectory::where('statusenabled', true)
->whereNull('status_action')
->count();
return response()->json([
'status' => true,
'count' => $count,
'message' => 'Berhasil mendapatkan data'
]);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => 'Terdapat kesalahan!'
]);
}
}
}

View File

@ -9,7 +9,7 @@ class LogActivityController extends Controller
{
public function index(){
$data =[
'title' => 'Log Activity'
'title' => 'Log Aktivitas'
];
return view('logActivity.index', $data);
}

View File

@ -3,6 +3,7 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\AksesFileDetail;
class AksesFile extends Model
{
@ -21,4 +22,9 @@ class AksesFile extends Model
public function akses(){
return $this->belongsTo(UnitKerja::class, 'unit_akses', 'id')->select('id', 'name');
}
public function details()
{
return $this->hasMany(AksesFileDetail::class, 'akses_file_id', 'akses_file_id');
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\UnitKerja;
class AksesFileDetail extends Model
{
protected $connection = 'dbDirectory';
protected $table = 'public.akses_file_unit_detail';
public $timestamps = false;
protected $primaryKey = 'id';
protected $guarded = ['id'];
public function unit()
{
return $this->belongsTo(UnitKerja::class, 'id_unit_kerja', 'id')->select('id', 'name');
}
}

View File

@ -103,13 +103,36 @@ function editAkses(e){
const data = $(e).data();
new bootstrap.Modal(modalEdit).show();
formEditAkses.attr('action', `/akses/${data.akses_file_id}`)
$("#akses_id_edit").val(data.akses === 1 ? 'all' : 'unit')
$("#unit_akses_edit").empty().trigger('change');
$("#unit_akses_wrapper_edit").addClass('d-none');
selectOptionPegawaiEdit()
selectOptionUnitKerjaEdit()
if (data.pegawai_id) {
setOldSelect2Value('#pegawai_id_edit', data.pegawai_id, data.pegawai_nama);
}
fetch(`/akses/${data.akses_file_id}`)
.then(async(res) => {
const responseData = await res.json();
if (!responseData.status) {
throw new Error(responseData.message || 'Gagal memuat data akses.');
}
const detail = responseData.data;
if (detail?.akses_type === 'all') {
$("#akses_all_edit").prop('checked', true);
} else {
$("#akses_unit_edit").prop('checked', true);
}
toggleUnitAksesEdit();
if (detail?.akses_type === 'unit' && Array.isArray(detail.units)) {
setOldSelect2Values('#unit_akses_edit', detail.units);
}
})
.catch(() => {
$("#akses_all_edit").prop('checked', true);
toggleUnitAksesEdit();
});
}
@ -143,6 +166,46 @@ function selectOptionPegawaiEdit() {
});
}
function selectOptionUnitKerjaEdit() {
let selectUnit = $(`#unit_akses_edit`);
if (selectUnit.data('select2')) return;
selectUnit.select2({
placeholder: '-- Pilih Unit Kerja --',
allowClear:true,
width: '100%',
dropdownParent: selectUnit.parent(),
ajax:{
url : '/select-unit-kerja',
dataType: 'json',
delay: 250,
data: function(params){
return { q: params.term }
},
processResults: function(data){
return {
results : data?.data.map(item => ({
id: item.id,
text: item.name,
}))
}
},
cache: true,
},
minimumInputLength: 1,
});
}
function toggleUnitAksesEdit() {
const wrapper = $("#unit_akses_wrapper_edit");
const unitSelect = $("#unit_akses_edit");
const isUnit = $("#akses_unit_edit").is(':checked');
if (isUnit) {
wrapper.removeClass('d-none');
} else {
wrapper.addClass('d-none');
unitSelect.val(null).trigger('change');
}
}
function setOldSelect2Value(selector, id, text) {
@ -151,6 +214,16 @@ function setOldSelect2Value(selector, id, text) {
$(selector).append(option).trigger('change')
}
function setOldSelect2Values(selector, items) {
if (!Array.isArray(items) || items.length === 0) return;
items.forEach(item => {
if (!item?.id || !item?.text) return;
let option = new Option(item.text, item.id, true, true);
$(selector).append(option);
});
$(selector).trigger('change')
}
formEditAkses.on('submit', function(e){
e.preventDefault();

View File

@ -25,15 +25,13 @@
<i class="fa-solid fa-trash"></i>
</button>
`
buttons += `
<button class="btn btn-sm btn-primary me-2" onclick="editAkses(this)"
data-akses_file_id="${row.akses_file_id}" data-akses="${row?.all_akses ? 1 : row?.unit_akses}"
data-pegawai_id="${row?.pegawai_id}"
data-pegawai_nama="${row?.pegawai?.namalengkap}"
data-unit_id="${row?.unit_akses}"
data-unit_nama="${row?.akses?.name}"
>
data-unit_nama="${row?.akses?.name}">
<i class="fa-solid fa-pencil"></i>
</button>`
return `
@ -50,7 +48,13 @@
{
title:"Akses",
formatter:function(value, row){
return row?.all_akses ? 'Semua Akses' : row?.akses?.name;
if (row?.all_akses) return 'Semua Unit';
const units = (row?.details || [])
.filter(detail => detail?.statusenabled)
.map(detail => detail?.unit?.name)
.filter(Boolean);
if (units.length > 0) return units.join(', ');
return row?.akses?.name || '-';
}
}
],

View File

@ -1,5 +1,6 @@
$(document).ready(function() {
selectOptionPegawai(0)
selectOptionUnitKerja(0)
});
function selectOptionPegawai(colCount) {
@ -31,6 +32,46 @@ function selectOptionPegawai(colCount) {
});
}
function selectOptionUnitKerja(colCount) {
let selectUnit = $(`#unit_akses_${colCount}`);
selectUnit.select2({
placeholder: '-- Pilih Unit Kerja --',
allowClear: true,
width: '100%',
dropdownParent: selectUnit.parent(),
ajax:{
url : '/select-unit-kerja',
dataType: 'json',
delay: 250,
data: function(params){
return { q: params.term }
},
processResults: function(data){
return {
results : data?.data.map(item => ({
id: item.id,
text: item.name,
}))
}
},
cache: true,
},
minimumInputLength: 1,
});
}
function toggleUnitAkses(colCount) {
const wrapper = $(`#unit_akses_wrapper_${colCount}`);
const unitSelect = $(`#unit_akses_${colCount}`);
const isUnit = $(`#akses_unit_${colCount}`).is(':checked');
if (isUnit) {
wrapper.removeClass('d-none');
} else {
wrapper.addClass('d-none');
unitSelect.val(null).trigger('change');
}
}
let colCount = 1;
@ -42,18 +83,38 @@ function addForm(){
html += `
<div class="row mt-3" id="col-${colCount}">
<hr/>
<div class="col-md-6 mb-2">
<div class="col-md-4 mb-2">
<label>Nama</label>
<select class="form-control" name="data[${colCount}][pegawai_id]" id="pegawai_id_${colCount}" required>
</select>
</div>
<div class="col-md-4 mb-2">
<label>Akses</label>
<select class="form-control" name="data[${colCount}][akses]" id="akses_id_${colCount}" required>
<option value="" disable>Select Choose</option>
<option value="all">Semua Akses</option>
<option value="unit">By Unit Akses</option>
<div class="col-12 col-md-2">
<label class="form-label mb-1 d-block">Akses</label>
<div class="d-flex flex-wrap gap-3">
<div class="form-check">
<input class="form-check-input" type="radio"
name="data[${colCount}][akses]" id="akses_all_${colCount}" value="all" checked
onchange="toggleUnitAkses(${colCount})">
<label class="form-check-label" for="akses_all_${colCount}">
Semua Akses
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="data[${colCount}][akses]" id="akses_unit_${colCount}" value="unit"
onchange="toggleUnitAkses(${colCount})">
<label class="form-check-label" for="akses_unit_${colCount}">
By Unit Akses
</label>
</div>
</div>
<small class="text-muted">Pilih salah satu.</small>
</div>
<div class="col-md-4 mb-2 d-none" id="unit_akses_wrapper_${colCount}">
<label>Unit Kerja</label>
<select class="form-control" name="data[${colCount}][unit_akses][]" id="unit_akses_${colCount}" multiple>
</select>
<small class="text-muted">Bisa pilih lebih dari satu.</small>
</div>
<div class="col-md-2">
<button type="button" class="btn btn-danger mt-3 me-2" onclick="removeCol(${colCount})"><i class="fa-solid fa-trash"></i></button>
@ -63,6 +124,7 @@ function addForm(){
`
col.append(html)
selectOptionPegawai(colCount)
selectOptionUnitKerja(colCount)
colCount++;
}
@ -71,4 +133,3 @@ function addForm(){
function removeCol(count){
$(`#col-${count}`).remove()
}

View File

@ -37,10 +37,10 @@ $(document).ready(function() {
});
// --- isi default unit kerja ---
if(authUnitKerja){
let option = new Option(authUnitKerja.name, authUnitKerja.id, true, true);
$('.unit_kerja').append(option).trigger('change');
}
// if(authUnitKerja){
// let option = new Option(authUnitKerja.name, authUnitKerja.id, true, true);
// $('.unit_kerja').append(option).trigger('change');
// }
let initialUnit = $('.unit_kerja').val();
if(initialUnit){

View File

@ -273,7 +273,7 @@ function downloadMultiple(){
URL.revokeObjectURL(url);
})
.catch(err => {
Swal.fire({ icon: 'error', title : 'Gagal mengunduh' })
Swal.fire({ icon: 'error', title : err.message })
})
}

View File

@ -0,0 +1,307 @@
document.addEventListener('DOMContentLoaded', () => {
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '' };
const tbody = document.getElementById('tablePendingFile');
const paginationEl = document.getElementById('paginationControls');
const summaryEl = document.getElementById('tableSummary');
const pageSizeSelect = document.getElementById('tablePageSize');
const startDateInput = document.getElementById('startDate');
const endDateInput = document.getElementById('endDate');
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
if (pageSizeSelect) {
const initialSize = parseInt(pageSizeSelect.value);
if (!isNaN(initialSize)) tableState.pageSize = initialSize;
pageSizeSelect.addEventListener('change', (e) => {
const val = parseInt(e.target.value);
if (!isNaN(val) && val > 0) {
tableState.pageSize = val;
tableState.page = 1;
fetchData();
}
});
}
window.applyDateFilter = function(){
tableState.startDate = startDateInput.value || '';
tableState.endDate = endDateInput.value || '';
tableState.page = 1;
fetchData();
}
function formatTanggal(dateString) {
if (!dateString) return '-';
const d = new Date(dateString);
return d.toLocaleDateString('id-ID', {
day: '2-digit',
month: 'short',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
function buildRow(item){
let tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
const aksi = `
<div class="d-flex gap-1">
<button class="btn btn-sm btn-success" onclick="approvePending('${item.file_directory_id}', '${item.fileName || ''}')">
<i class="fa-solid fa-check"></i>
</button>
<button class="btn btn-sm btn-danger" onclick="rejectPending('${item.file_directory_id}', '${item.fileName || ''}')">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
`;
return `
<tr>
<td>${aksi}</td>
<td>${item.no_dokumen || '-'}</td>
<td><a href="#" class="file-link"
data-file="${item.file}"
data-fileName="${item.fileName}"
data-id="${item.file_directory_id}"
data-no_dokumen="${item.no_dokumen || '-'}"
data-tanggal_terbit="${item.tanggal_terbit || '-'}"
data-permission_file="${item.permission_file || '-'}">${item.fileName}</a></td>
<td>${item.folder || '-'}</td>
<td>${item.part || '-'}</td>
<td class="text-nowrap">${tanggal}</td>
</tr>
`;
}
function renderPagination(totalPages){
if (!paginationEl) return;
if (totalPages <= 1) {
paginationEl.innerHTML = '';
return;
}
const maxButtons = 5;
let start = Math.max(1, tableState.page - Math.floor(maxButtons/2));
let end = Math.min(totalPages, start + maxButtons - 1);
start = Math.max(1, end - maxButtons + 1);
let buttons = '';
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="prev" ${tableState.page === 1 ? 'disabled' : ''}></button>`;
for (let i = start; i <= end; i++) {
buttons += `<button class="btn btn-sm ${i === tableState.page ? 'btn-primary' : 'btn-outline-secondary'}" data-page="${i}">${i}</button>`;
}
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="next" ${tableState.page === totalPages ? 'disabled' : ''}></button>`;
paginationEl.innerHTML = `
<div class="d-flex align-items-center gap-2 flex-wrap">
<div class="btn-group" role="group">${buttons}</div>
<span class="small text-muted">Halaman ${tableState.page} dari ${totalPages}</span>
</div>
`;
}
if (paginationEl) {
paginationEl.addEventListener('click', (e) => {
const page = e.target.getAttribute('data-page');
if (!page) return;
if (page === 'prev' && tableState.page > 1) tableState.page--;
else if (page === 'next') {
if (tableState.page < tableState.lastPage) tableState.page++;
} else {
tableState.page = parseInt(page);
}
fetchData();
});
}
function renderTable(){
const pageData = tableState.data || [];
if (pageData.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="4" class="text-center text-muted py-4">
Tidak ada data
</td>
</tr>
`;
} else {
tbody.innerHTML = pageData.map(buildRow).join('');
}
const from = tableState.total === 0 ? 0 : ((tableState.page - 1) * tableState.pageSize) + 1;
const to = Math.min(((tableState.page - 1) * tableState.pageSize) + pageData.length, tableState.total);
if (summaryEl) {
summaryEl.textContent = tableState.total ? `Menampilkan ${from} - ${to} dari ${tableState.total} data` : 'Tidak ada data';
}
renderPagination(tableState.lastPage || 1);
}
let searchDebounce;
window.debouncedTableSearch = function(value){
clearTimeout(searchDebounce);
searchDebounce = setTimeout(() => {
tableState.search = value.trim();
tableState.page = 1;
fetchData();
}, 250);
}
window.refreshLog = function(){
tableState.search = '';
tableState.startDate = '';
tableState.endDate = '';
document.getElementById('tableSearch').value = '';
startDateInput.value = '';
endDateInput.value = '';
tableState.page = 1;
fetchData();
}
function fetchData(){
if (summaryEl) summaryEl.textContent = 'Memuat data...';
const params = new URLSearchParams({
page: tableState.page,
per_page: tableState.pageSize,
keyword: tableState.search || '',
start_date: tableState.startDate || '',
end_date: tableState.endDate || ''
});
fetch(`/datatable/pending-file?${params.toString()}`)
.then(res => res.json())
.then(data => {
tableState.data = data?.data || [];
tableState.lastPage = data?.pagination?.last_page || 1;
tableState.total = data?.pagination?.total || 0;
renderTable();
})
.catch(err => {
console.error(err);
if (summaryEl) summaryEl.textContent = 'Gagal memuat data';
});
}
window.approvePending = function(id, fileName){
Swal.fire({
title: 'Approve dokumen?',
text: fileName || 'Dokumen akan disetujui.',
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Approve',
cancelButtonText: 'Batal',
}).then((result) => {
if (!result.isConfirmed) return;
fetch(`/pending-file/${id}/approve`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken,
'Content-Type': 'application/json'
},
}).then(async(res) => {
const data = await res.json();
if (!res.ok || !data?.status) {
throw new Error(data?.message || 'Gagal approve.');
}
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: data.message || 'Dokumen disetujui.',
timer: 1500,
showConfirmButton: false
});
countData()
fetchData();
}).catch((err) => {
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message || 'Terjadi kesalahan.'
});
});
});
}
window.rejectPending = function(id, fileName){
Swal.fire({
title: 'Reject dokumen?',
text: fileName || 'Dokumen akan ditolak.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Reject',
cancelButtonText: 'Batal',
}).then((result) => {
if (!result.isConfirmed) return;
fetch(`/pending-file/${id}/reject`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken,
'Content-Type': 'application/json'
},
}).then(async(res) => {
const data = await res.json();
if (!res.ok || !data?.status) {
throw new Error(data?.message || 'Gagal reject.');
}
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: data.message || 'Dokumen ditolak.',
timer: 1500,
showConfirmButton: false
});
countData()
fetchData();
}).catch((err) => {
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message || 'Terjadi kesalahan.'
});
});
});
}
fetchData();
});
document.addEventListener('click', function(e){
if(e.target.matches('.file-link')){
e.preventDefault();
let fileUrl = e.target.getAttribute('data-file');
let noDokumen = e.target.getAttribute('data-no_dokumen')
let tanggalTerbit = e.target.getAttribute('data-tanggal_terbit')
let permissionFile = e.target.getAttribute('data-permission_file')
let fileName = e.target.getAttribute('data-fileName')
currentFile = fileUrl;
idDirectory = e.target.getAttribute('data-id');
const titleEl = document.getElementById('confirm_preview_file');
if (titleEl) titleEl.textContent = fileName;
// set footer info
const noEl = document.getElementById('confirm-upload-dokumen');
if (noEl) noEl.textContent = noDokumen;
const tglEl = document.getElementById('confirm-time-dokumen');
if (tglEl) tglEl.textContent = tanggalTerbit;
const permEl = document.getElementById('confirm-permission');
if (permEl) {
const publicDoc = isPublic(permissionFile);
permEl.textContent = publicDoc ? 'Bisa dilihat unit lain' : 'Hanya unit ini';
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
}
let previewBox = document.getElementById('file-preview');
previewBox.innerHTML = `<iframe src="/file-preview/${idDirectory}" width="100%" height="500px" style="border:none;"></iframe>`;
$("#previewModal").modal('show')
}
if(e.target.matches('#btn-view-full')){
window.open(`/file-preview/${idDirectory}`, '_blank');
}
})
function isPublic(permissionVal){
if(permissionVal === null || permissionVal === undefined) return false;
const val = String(permissionVal).toLowerCase();
return val === '1' || val === 'true' || val === 'iya' || val === 'yes';
}

View File

@ -4,7 +4,7 @@
<!-- Modal Header -->
<div class="modal-header">
<h1 class="modal-title fs-5">Aksi</h1>
<h1 class="modal-title fs-5">Tambah Akses</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
@ -13,25 +13,51 @@
@csrf
<div class="modal-body">
<div class="container">
<div class="row">
<div class="col-md-6 mb-2">
<label>Nama</label>
<div class="border rounded-3 p-3 mb-2">
<div class="row g-3 align-items-end">
<div class="col-md-4 mb-2">
<label class="form-label">Nama</label>
<select class="form-control" name="data[0][pegawai_id]" id="pegawai_id_0" required>
</select>
<small class="text-muted">Cari nama pegawai.</small>
</div>
<div class="col-md-6 mb-2">
<label>Akses</label>
<select class="form-control" name="data[0][akses]" id="akses_id_0" required>
<option value="" disable>Select Choose</option>
<option value="all">Semua Akses</option>
<option value="unit">By Unit Akses</option>
<div class="col-12 col-md-4">
<label class="form-label mb-1 d-block">Akses</label>
<div class="d-flex flex-wrap gap-3">
<div class="form-check">
<input class="form-check-input" type="radio"
name="data[0][akses]" id="akses_all_0" value="all" checked
onchange="toggleUnitAkses(0)">
<label class="form-check-label" for="akses_all_0">
Semua Akses
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="data[0][akses]" id="akses_unit_0" value="unit"
onchange="toggleUnitAkses(0)">
<label class="form-check-label" for="akses_unit_0">
By Unit Akses
</label>
</div>
</div>
<small class="text-muted">Pilih salah satu.</small>
</div>
<div class="col-md-4 mb-2 d-none" id="unit_akses_wrapper_0">
<label class="form-label">Unit Kerja</label>
<select class="form-control" name="data[0][unit_akses][]" id="unit_akses_0" multiple>
</select>
<small class="text-muted">Bisa pilih lebih dari satu.</small>
</div>
</div>
<div id="col_add_akses"></div>
<button type="button" class="btn btn-outline-primary btn-sm mt-2" onclick="addForm()">
+ Tambah Form
</button>
+ Tambah Form
</button>
</div>
</div>
</div>

View File

@ -4,7 +4,7 @@
<!-- Modal Header -->
<div class="modal-header">
<h1 class="modal-title fs-5">Aksi</h1>
<h1 class="modal-title fs-5">Edit Akses</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
@ -14,20 +14,43 @@
@method('PUT')
<div class="modal-body">
<div class="container">
<div class="row">
<div class="col-md-6 mb-2">
<label>Nama</label>
<select class="form-control" name="pegawai_id" id="pegawai_id_edit" required>
</select>
</div>
<div class="col-md-6 mb-2">
<label>Akses</label>
<select class="form-control" name="akses" id="akses_id_edit" required>
<option value="" disable>Select Choose</option>
<option value="all">Semua Akses</option>
<option value="unit">By Unit Akses</option>
</select>
</div>
<div class="border rounded-3 p-3">
<div class="row g-3 align-items-end">
<div class="col-md-4 mb-2">
<label class="form-label">Nama</label>
<select class="form-control" name="pegawai_id" id="pegawai_id_edit" required>
</select>
<small class="text-muted">Cari nama pegawai.</small>
</div>
<div class="col-12 col-md-2">
<label class="form-label mb-1 d-block">Akses</label>
<div class="d-flex flex-wrap gap-3">
<div class="form-check">
<input class="form-check-input" type="radio"
name="akses" id="akses_all_edit" value="all"
onchange="toggleUnitAksesEdit()">
<label class="form-check-label" for="akses_all_edit">
Semua Akses
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="akses" id="akses_unit_edit" value="unit"
onchange="toggleUnitAksesEdit()">
<label class="form-check-label" for="akses_unit_edit">
By Unit Akses
</label>
</div>
</div>
<small class="text-muted">Pilih salah satu.</small>
</div>
<div class="col-12 col-md-6 d-none" id="unit_akses_wrapper_edit">
<label class="form-label">Unit Kerja</label>
<select class="form-control" name="unit_akses[]" id="unit_akses_edit" multiple>
</select>
<small class="text-muted">Bisa pilih lebih dari satu.</small>
</div>
</div>
</div>
</div>
</div>

View File

@ -67,13 +67,13 @@
<div class="row g-3 align-items-end">
<div class="col-md-4">
<label for="unit_kerja" class="form-label fw-semibold text-muted small">Unit Kerja</label>
<select class="form-control unit_kerja" id="unit_kerja"{{ ($allAkses && ($allAkses->all_akses || $allAkses->unit_akses)) ? '' : 'disabled' }}>
<select class="form-control unit_kerja" id="unit_kerja">
</select>
</div>
<div class="col-md-4">
<label for="sub_unit_kerja" class="form-label fw-semibold text-muted small">Sub Unit Kerja</label>
<select class="form-control sub_unit_kerja" id="sub_unit_kerja" @if($allAkses && ($allAkses->all_akses || $allAkses->unit_akses)) multiple="multiple" @else disabled @endif>
<select class="form-control sub_unit_kerja" id="sub_unit_kerja" multiple="multiple">
</select>
</div>
@ -265,19 +265,6 @@
}
// $("#download-file").off('click').on('click', function(){
// if(currentFile){
// let link = document.createElement('a');
// link.href = 'file/' + currentFile; // alamat file
// link.download = currentFile.split('/').pop(); // nama file otomatis
// document.body.appendChild(link);
// link.click();
// document.body.removeChild(link);
// }else{
// console.error('error');
// }
// })
});

View File

@ -38,7 +38,8 @@
<tr>
<th style="width:5%;" class="text-center">#</th>
<th style="width:30%;">Unit</th>
<th style="width:50%;">Folder</th>
<th style="width:30%;">Sub Unit</th>
<th style="width:20%;">Folder</th>
<th style="width:15%;" class="text-center">Jumlah</th>
</tr>
</thead>
@ -102,6 +103,7 @@ function fetchRecap(){
<tr>
${i === 0 ? `<td rowspan="${row.data.length}" class="text-center align-middle fw-semibold">${idx+1}</td>` : ''}
${i === 0 ? `<td rowspan="${row.data.length}" class="fw-semibold">${row.unit || '-'}</td>` : ''}
<td>${f.subUnit || '-'}</td>
<td>${f.folder || '-'}</td>
<td class="text-center fw-bold">${f.count || 0}</td>
</tr>

View File

@ -272,11 +272,11 @@
width: '100%',
});
// --- isi default unit kerja ---
if(authUnitKerja){
let option = new Option(authUnitKerja.name, authUnitKerja.id, true, true);
$('.unit_kerja').append(option).trigger('change');
}
// // --- isi default unit kerja ---
// if(authUnitKerja){
// let option = new Option(authUnitKerja.name, authUnitKerja.id, true, true);
// $('.unit_kerja').append(option).trigger('change');
// }
let initialUnit = $('.unit_kerja').val();
if(initialUnit){

View File

@ -18,13 +18,13 @@
</li>
<li class="sidebar-item">
<a class="sidebar-link" href="/" aria-expanded="false">
<i class="ti ti-atom"></i>
<i class="ti ti-dashboard"></i>
<span class="hide-menu">Dashboard</span>
</a>
</li>
<li class="sidebar-item">
<a class="sidebar-link" href="/new" aria-expanded="false">
<i class="ti ti-atom"></i>
<i class="ti ti-layout-dashboard"></i>
<span class="hide-menu">Dashboard V2</span>
</a>
</li>
@ -59,7 +59,7 @@
href="/akses" aria-expanded="false">
<div class="d-flex align-items-center gap-3">
<span class="d-flex">
<i class="ti ti-layout-grid"></i>
<i class="ti ti-lock-access"></i>
</span>
<span class="hide-menu">Akses</span>
</div>
@ -71,9 +71,9 @@
href="/log-activity" aria-expanded="false">
<div class="d-flex align-items-center gap-3">
<span class="d-flex">
<i class="ti ti-layout-grid"></i>
<i class="ti ti-activity"></i>
</span>
<span class="hide-menu">Log Aktivity</span>
<span class="hide-menu">Log Aktivitas</span>
</div>
</a>
</li>
@ -83,15 +83,54 @@
href="/recap" aria-expanded="false">
<div class="d-flex align-items-center gap-3">
<span class="d-flex">
<i class="ti ti-layout-grid"></i>
<i class="ti ti-report-analytics"></i>
</span>
<span class="hide-menu">Data Rekap</span>
</div>
</a>
</li>
<li class="sidebar-item">
<a class="sidebar-link d-flex align-items-center justify-content-between"
href="/pending-file" aria-expanded="false">
<!-- Left -->
<div class="d-flex align-items-center gap-3">
<i class="ti ti-clock sidebar-icon"></i>
<span class="hide-menu">Persetujuan</span>
</div>
<!-- Right Badge -->
<span class="badge bg-danger rounded-pill sidebar-badge" id="pendingCountBadge">
0
</span>
</a>
</li>
</ul>
</nav>
<!-- End Sidebar navigation -->
</div>
<!-- End Sidebar scroll-->
</aside>
<script>
function countData(){
const badge = document.getElementById('pendingCountBadge');
if (!badge) return;
fetch('/data/count-pending')
.then(res => res.json())
.then(data => {
const count = data?.count ?? 0;
badge.textContent = count;
if (count <= 0) {
badge.classList.add('d-none');
} else {
badge.classList.remove('d-none');
}
})
.catch(() => {
badge.classList.add('d-none');
});
}
countData();
</script>

View File

@ -4,7 +4,7 @@
<div class="col-md-12">
<div class="card">
<div class="card-header d-flex align-items-center justify-content-between">
<h4 class="mb-0">Log Activity</h4>
<h4 class="mb-0">Log Aktivitas</h4>
</div>
<div class="card-body p-3">
<div class="d-flex flex-column flex-md-row align-items-md-center gap-2 mb-3 flex-wrap">

View File

@ -0,0 +1,68 @@
@extends('layout.main')
@section('body_main')
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header d-flex align-items-center justify-content-between">
<h4 class="mb-0">Data Pending</h4>
</div>
<div class="card-body p-3">
<div class="d-flex flex-column flex-md-row align-items-md-center gap-2 mb-3 flex-wrap">
<div class="input-group input-group-sm flex-grow-1" style="max-width:320px;">
<span class="input-group-text bg-white border-end-0">
<i class="fa fa-search text-muted"></i>
</span>
<input type="search"
id="tableSearch"
class="form-control border-start-0"
placeholder="Cari nama file / nomor dokumen"
oninput="debouncedTableSearch(this.value)">
</div>
<div class="d-flex align-items-center gap-2">
<label class="small mb-0 text-muted">Mulai</label>
<input type="date" id="startDate" class="form-control form-control-sm" onchange="applyDateFilter()">
</div>
<div class="d-flex align-items-center gap-2">
<label class="small mb-0 text-muted">Selesai</label>
<input type="date" id="endDate" class="form-control form-control-sm" onchange="applyDateFilter()">
</div>
<div class="d-flex align-items-center gap-2">
<select id="tablePageSize" class="form-select form-select-sm" style="width: auto;">
<option value="5">5</option>
<option value="10"selected>10</option>
<option value="20">20</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
<button class="btn btn-outline-secondary btn-sm" onclick="refreshLog()">
<i class="fa fa-rotate"></i> Refresh
</button>
<div class="small text-muted ms-md-auto" id="tableSummary"></div>
</div>
<div class="table-responsive" style="max-height: 55vh; overflow-y:auto;">
<table class="table table-sm table-hover align-middle mb-0" id="lastUpdatedTable">
<thead>
<tr>
<th>Aksi</th>
<th>No Dokumen</th>
<th>File</th>
<th>Folder</th>
<th>Unit/Sub Unit</th>
<th>Tanggal</th>
</tr>
</thead>
<tbody id="tablePendingFile">
<!-- data dari fetch masuk sini -->
</tbody>
</table>
</div>
<div class="d-flex flex-column flex-md-row align-items-md-center justify-content-between gap-2 mt-3" id="paginationControls"></div>
</div>
</div>
</div>
</div>
@include('pendingFile.modal.view')
<script src="{{ ver('/js/pendingFile/index.js') }}"></script>
@endsection

View File

@ -0,0 +1,58 @@
<!-- Modal Preview -->
<div class="modal fade" id="previewModal" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<!-- Header -->
<div class="modal-header">
<h6 class="modal-title" id="previewModalLabel">
📄 Preview <strong id="confirm_preview_file"></strong>
</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Body -->
<div class="modal-body p-2" style="min-height:250px; max-height:70vh; overflow:auto;">
<div id="file-preview"
class="text-center text-muted d-flex justify-content-center align-items-center"
style="height:100%;">
<p>📂 Pilih file untuk melihat preview</p>
</div>
</div>
<!-- Footer -->
<div class="modal-footer d-flex justify-content-between align-items-center">
<div class="small text-muted">
<span class="me-3">
Nomor Dokumen:
<strong id="confirm-upload-dokumen" class="text-dark">-</strong>
</span>
<span class="me-3">
Tanggal Terbit:
<strong id="confirm-time-dokumen" class="text-dark">-</strong>
</span>
<span>
Akses Dokumen:
<span id="confirm-permission" class="badge bg-secondary">-</span>
</span>
</div>
<!-- Button -->
<div class="d-flex gap-2">
<button type="button" class="btn btn-sm btn-outline-primary" id="btn-view-full">
Lihat Full
</button>
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">
Tutup
</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -40,6 +40,12 @@ Route::middleware(['auth'])->group(function(){
Route::get('/recap', [DashboardController::class, 'recapView']);
Route::get('/data/recap', [DashboardController::class, 'recapData']);
Route::get('/pending-file', [DashboardController::class, 'pendingFile']);
Route::get('/datatable/pending-file', [DashboardController::class, 'dataPendingFile']);
Route::post('/pending-file/{id}/approve', [DashboardController::class, 'approvePendingFile']);
Route::post('/pending-file/{id}/reject', [DashboardController::class, 'rejectPendingFile']);
Route::get('/data/count-pending', [DashboardController::class, 'countDataPending']);
});
Route::get('/login', [AuthController::class, 'index'])->name('login');