354 lines
14 KiB
JavaScript
354 lines
14 KiB
JavaScript
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 statusBadge(status){
|
||
if (status === 'rejected') return '<span class="badge bg-danger">Rejected</span>';
|
||
if (status === 'revised') return '<span class="badge bg-info">Revised</span>';
|
||
return '<span class="badge bg-warning text-dark">Pending</span>';
|
||
}
|
||
function aksesBadge(akses){
|
||
if (akses){
|
||
return '<span class="badge bg-success">Umum</span>';
|
||
} else{
|
||
return '<span class="badge bg-primary">Internal Unit</span>';
|
||
}
|
||
}
|
||
|
||
function safeText(val){
|
||
return val ? String(val) : '-';
|
||
}
|
||
|
||
function buildRow(item){
|
||
const 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>${item?.status_action !== "rejected" ? aksi : ''}</td>
|
||
<td>${safeText(item.no_dokumen)}</td>
|
||
<td>${statusBadge(item?.status_action)}</td>
|
||
<td>${aksesBadge(item?.permission_file)}</td>
|
||
<td><a href="#" class="file-link"
|
||
data-file="${item.file}"
|
||
data-fileName="${item.fileName}"
|
||
data-id="${item.file_directory_id}"
|
||
data-no_dokumen="${safeText(item.no_dokumen)}"
|
||
data-tanggal_terbit="${safeText(item.tanggal_terbit)}"
|
||
data-permission_file="${safeText(item.permission_file)}">${safeText(item.fileName)}</a></td>
|
||
<td>${safeText(item.folder)}</td>
|
||
<td>${safeText(item.part)}</td>
|
||
<td class="text-nowrap">${tanggal}</td>
|
||
<td>${safeText(item.pegawai_nama_entry)}</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="9" 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',
|
||
input: 'textarea',
|
||
inputLabel: 'Catatan',
|
||
inputPlaceholder: 'Tulis alasan atau catatan revisi...',
|
||
inputAttributes: {
|
||
'aria-label': 'Catatan'
|
||
},
|
||
preConfirm: (value) => {
|
||
const revision = (value || '').trim();
|
||
if (!revision) {
|
||
Swal.showValidationMessage('Catatan revisi wajib diisi.');
|
||
}
|
||
return revision;
|
||
}
|
||
}).then((result) => {
|
||
if (!result.isConfirmed) return;
|
||
fetch(`/pending-file/${id}/reject`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'X-CSRF-TOKEN': csrfToken,
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
revision: result.value
|
||
})
|
||
}).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.'
|
||
});
|
||
});
|
||
});
|
||
}
|
||
window.infoReject = function(id, fileName){
|
||
const item = id;
|
||
const revision = item?.revision ? String(item.revision) : 'Tidak ada catatan revisi.';
|
||
Swal.fire({
|
||
title: 'Catatan Revisi',
|
||
text: revision,
|
||
icon: 'info',
|
||
confirmButtonText: 'Tutup'
|
||
});
|
||
}
|
||
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';
|
||
}
|