2026-02-03 16:17:23 +07:00

502 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

document.addEventListener('DOMContentLoaded', () => {
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '' };
const tbody = document.getElementById('tablePengajuanFile');
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');
const editForm = document.getElementById('formEditPengajuanFile');
const editUnitSelect = $('#edit_id_unit_kerja');
const editSubUnitSelect = $('#edit_id_sub_unit_kerja');
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'
});
}
function buildRow(item){
let tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
let tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
let tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
const aksi = `
<div class="d-flex gap-1">
<button href="#" class="btn btn-sm btn-primary" onclick="infoDok(this)"
data-file="${item.file}"
data-fileName="${item.nama_dokumen}"
data-id="${item.file_directory_id}"
data-no_dokumen="${item.no_dokumen || '-'}"
data-tanggal_terbit="${item.tanggal_terbit || '-'}"
data-permission_file="${item.permission_file || '-'}">
<i class="fa-solid fa-file-pdf"></i>
</button>
<button class="btn btn-sm btn-info" onclick="infoReject('${item.file_directory_id}')">
<i class="fa-solid fa-circle-info"></i>
</button>
<button class="btn btn-sm btn-primary" onclick="editFileReject('${item.file_directory_id}')">
<i class="fa-solid fa-pen-to-square"></i>
</button>
</div>
`;
return `
<tr>
<td>${aksi}</td>
<td>${item.no_dokumen || '-'}</td>
<td>
<button class="btn btn-sm
${item?.status_action === "rejected" ? 'btn-danger' :
item?.status_action === "revised" ? 'btn-info' :
'btn-warning'}">
${item?.status_action === "rejected" ? 'Rejected' :
item?.status_action === "revised" ? 'Revised' :
'Pending'}
</button>
</td>
<td>${aksesBadge(item?.permission_file)}</td>
<td><a href="#" class="file-link"
data-file="${item.file}"
data-fileName="${item.nama_dokumen}"
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.nama_dokumen}</a></td>
<td>${item.folder || '-'}</td>
<td>${item.part || '-'}</td>
<td class="text-nowrap">${tanggalTerbit}</td>
<td class="text-nowrap">${tanggalExp}</td>
<td class="text-nowrap">${tanggal}</td>
</tr>
`;
}
function aksesBadge(akses){
if (akses){
return '<span class="badge bg-success">Umum</span>';
} else{
return '<span class="badge bg-primary">Internal Unit</span>';
}
}
function getItemById(id){
return (tableState.data || []).find((row) => String(row.file_directory_id) === String(id));
}
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="10" 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/pengajuan-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.infoReject = function(id){
const item = getItemById(id);
const revision = item?.revision ? String(item.revision) : 'Tidak ada catatan revisi.';
Swal.fire({
title: 'Catatan Revisi',
text: revision,
icon: 'info',
confirmButtonText: 'Tutup'
});
}
window.infoDok = function(e){
let fileUrl = $(e).data('file');
let noDokumen = $(e).data('no_dokumen')
let tanggalTerbit = $(e).data('tanggal_terbit')
let permissionFile = $(e).data('permission_file')
let fileName = $(e).data('fileName')
currentFile = fileUrl;
idDirectory = $(e).data('id');
const titleEl = document.getElementById('confirm_preview_file');
if (titleEl) titleEl.textContent = fileName;
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 ? 'Umum' : 'Internal Unit';
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
}
let previewBox = document.getElementById('file-preview');
previewBox.innerHTML = `<div id="pdfWrap" style="height:500px; overflow:auto; background:#f7f7f7; padding:8px;">
<div id="pdfPages"></div>`;
openPreview(idDirectory);
$("#previewModal").modal('show')
}
function initEditSelects(){
if (editUnitSelect.length) {
editUnitSelect.select2({
placeholder: '-- Pilih Unit Kerja --',
allowClear: true,
width: '100%',
dropdownParent: $('#modalEditPengajuanFile'),
ajax: {
url: '/select-unit-kerja-mapping',
dataType: 'json',
delay: 250,
data: function (params) {
return { q: params.term || '' };
},
processResults: function (data) {
return {
results: (data?.data || []).map(item => ({
id: `${item.id}/${item.name}`,
text: item.name
}))
};
},
cache: true
},
minimumInputLength: 0
});
}
if (editSubUnitSelect.length) {
editSubUnitSelect.select2({
placeholder: '-- Pilih Sub Unit Kerja --',
allowClear: true,
width: '100%',
dropdownParent: $('#modalEditPengajuanFile')
});
}
editUnitSelect.on('change', function(){
const val = $(this).val();
if (!val) return;
const unitId = String(val).split('/')[0];
loadEditSubUnit(unitId, null, null);
});
}
function loadEditSubUnit(unitId, selectedSubId, selectedSubName){
editSubUnitSelect.empty().append('<option value="" disabled selected>-- Pilih Sub Unit Kerja --</option>');
if (!unitId) return;
$.ajax({
url: `/select-sub-unit-kerja-mapping/${unitId}`,
method: 'GET',
success: function(response) {
if (response?.data) {
response.data.forEach(unit => {
const optVal = `${unit.id}/${unit.name}`;
const isSelected = selectedSubId && String(unit.id) === String(selectedSubId);
const option = new Option(unit.name, optVal, false, isSelected);
editSubUnitSelect.append(option);
});
if (selectedSubId && selectedSubName && editSubUnitSelect.find(`option[value="${selectedSubId}/${selectedSubName}"]`).length === 0) {
editSubUnitSelect.append(new Option(selectedSubName, `${selectedSubId}/${selectedSubName}`, true, true));
}
editSubUnitSelect.trigger('change');
}
}
});
}
window.editFileReject = function(id){
const item = getItemById(id);
if (!item) {
Swal.fire({ icon: 'error', title: 'Gagal', text: 'Data tidak ditemukan.' });
return;
}
const idEl = document.getElementById('edit_file_directory_id');
const noEl = document.getElementById('edit_no_dokumen');
const namaEl = document.getElementById('edit_nama_dokumen');
const tglEl = document.getElementById('edit_tanggal_terbit');
const tglExpiredEl = document.getElementById('edit_tgl_expired');
const hasExpiredEl = document.getElementById('edit_has_expired');
const expiredFieldEl = document.getElementById('edit_expired_field');
const currentFileEl = document.getElementById('edit_current_file');
const permYes = document.getElementById('edit_perm_yes');
const permNo = document.getElementById('edit_perm_no');
const katEl = document.getElementById('edit_kategori');
if (idEl) idEl.value = item.file_directory_id || '';
if (noEl) noEl.value = item.no_dokumen || '';
if (namaEl) namaEl.value = item.nama_dokumen || '';
if (tglEl) tglEl.value = item.tanggal_terbit || '';
if (tglExpiredEl) tglExpiredEl.value = item.tgl_expired || '';
if (permYes && permNo) {
const isPublic = item.permission_file === true || item.permission_file === 1 || item.permission_file === '1';
permYes.checked = isPublic;
permNo.checked = !isPublic;
}
if (hasExpiredEl && expiredFieldEl) {
const hasExpired = !!item.tgl_expired;
hasExpiredEl.checked = hasExpired;
expiredFieldEl.classList.toggle('d-none', !hasExpired);
}
if (currentFileEl) {
const displayName = item.fileName || (item.file ? String(item.file).split('/').pop() : '');
currentFileEl.textContent = displayName ? `File saat ini: ${displayName}` : '';
}
const parts = (item.file || '').split('/');
const unitName = parts[0] || '';
const subName = parts[1] || '';
const kategoriName = parts[2] || '';
if (editUnitSelect.length && item.id_unit_kerja) {
const unitVal = `${item.id_unit_kerja}/${unitName}`;
editUnitSelect.append(new Option(unitName || 'Unit', unitVal, true, true)).trigger('change');
const unitId = String(item.id_unit_kerja);
loadEditSubUnit(unitId, item.id_sub_unit_kerja, subName);
}
if (katEl && item.master_kategori_directory_id) {
const katVal = `${item.master_kategori_directory_id}/${kategoriName}`;
if (katEl.querySelector(`option[value="${katVal}"]`)) {
katEl.value = katVal;
} else {
katEl.append(new Option(kategoriName || 'Kategori', katVal, true, true));
katEl.value = katVal;
}
}
const modalEl = document.getElementById('modalEditPengajuanFile');
if (modalEl) {
$("#modalEditPengajuanFile").modal('show');
}
}
const editHasExpired = document.getElementById('edit_has_expired');
if (editHasExpired) {
editHasExpired.addEventListener('change', () => {
const targetId = editHasExpired.getAttribute('data-target');
const container = targetId ? document.getElementById(targetId) : null;
if (container) {
container.classList.toggle('d-none', !editHasExpired.checked);
if (!editHasExpired.checked) {
const input = container.querySelector('input[type="date"]');
if (input) input.value = '';
}
}
});
}
if (editForm) {
editForm.addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('edit_file_directory_id')?.value;
if (!id) {
Swal.fire({ icon: 'error', title: 'Gagal', text: 'ID dokumen tidak ditemukan.' });
return;
}
const formData = new FormData(editForm);
fetch(`/pengajuan-file/${id}/update`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken
},
body: formData
}).then(async (res) => {
const data = await res.json();
if (!res.ok || !data?.status) {
throw new Error(data?.message || 'Gagal memperbarui data.');
}
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: data.message || 'Data berhasil diperbarui.',
timer: 1500,
showConfirmButton: false
});
$("#modalEditPengajuanFile").modal('hide');
fetchData();
}).catch((err) => {
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message || 'Terjadi kesalahan.'
});
});
});
}
initEditSelects();
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 ? 'Umum' : 'Internal Unit';
permEl.className = 'badge ' + (publicDoc ? 'bg-success' : 'bg-secondary');
}
let previewBox = document.getElementById('file-preview');
previewBox.innerHTML = `<div id="pdfWrap" style="height:500px; overflow:auto; background:#f7f7f7; padding:8px;">
<div id="pdfPages"></div>
</div>
`;
openPreview(idDirectory);
$("#previewModal").modal('show')
}
if(e.target.matches('#btn-view-full')){
window.open(`/full-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';
}