1694 lines
70 KiB
JavaScript
1694 lines
70 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
||
const tableState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '', mode: 'pengajuan' };
|
||
const historyState = { data: [], page: 1, pageSize: 10, search: '', lastPage: 1, total: 0, startDate: '', endDate: '', mode: 'history' };
|
||
const tbodyPengajuan = document.getElementById('tablePengajuanFile');
|
||
const tbodyHistory = document.getElementById('tableHistoryFile');
|
||
const paginationPengajuan = document.getElementById('paginationPengajuan');
|
||
const paginationHistory = document.getElementById('paginationHistory');
|
||
const summaryEl = document.getElementById('tableSummary');
|
||
const pageSizeSelect = document.getElementById('tablePageSize');
|
||
const startDateInput = document.getElementById('startDate');
|
||
const endDateInput = document.getElementById('endDate');
|
||
const tabsEl = document.getElementById('pengajuanTabs');
|
||
const titleEl = document.getElementById('pengajuanTitle');
|
||
const tabPengajuanEl = document.getElementById('tabPengajuan');
|
||
const tabHistoryEl = document.getElementById('tabHistory');
|
||
const selectAllCheckbox = document.getElementById('selectAllPengajuan');
|
||
const bulkDeleteBtn = document.getElementById('bulkDeleteBtn');
|
||
const clearSelectionBtn = document.getElementById('clearSelectionBtn');
|
||
const selectedCountEl = document.getElementById('selectedCount');
|
||
const bulkActionsEl = document.getElementById('pengajuanBulkActions');
|
||
const deleteDataEl = document.getElementById('deleteData');
|
||
const formCreate = document.getElementById('formFile');
|
||
const modalCreate = document.getElementById('modalCreateFile');
|
||
let colCount = 1;
|
||
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');
|
||
const selectedIds = new Set();
|
||
const isKomiteMutu = !!window.isKomiteMutu;
|
||
const isTurt = !!window.isTurt;
|
||
|
||
if (pageSizeSelect) {
|
||
const initialSize = parseInt(pageSizeSelect.value);
|
||
if (!isNaN(initialSize)) {
|
||
tableState.pageSize = initialSize;
|
||
historyState.pageSize = initialSize;
|
||
}
|
||
pageSizeSelect.addEventListener('change', (e) => {
|
||
const val = parseInt(e.target.value);
|
||
if (!isNaN(val) && val > 0) {
|
||
tableState.pageSize = val;
|
||
historyState.pageSize = val;
|
||
tableState.page = 1;
|
||
historyState.page = 1;
|
||
fetchData();
|
||
}
|
||
});
|
||
}
|
||
|
||
window.applyDateFilter = function(){
|
||
const start = startDateInput.value || '';
|
||
const end = endDateInput.value || '';
|
||
tableState.startDate = start;
|
||
tableState.endDate = end;
|
||
historyState.startDate = start;
|
||
historyState.endDate = end;
|
||
tableState.page = 1;
|
||
historyState.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 getSelectableIdsOnPage(){
|
||
return (tableState.data || []).map((row) => String(row.file_directory_id));
|
||
}
|
||
|
||
function updateSelectAllState(){
|
||
if (!selectAllCheckbox) return;
|
||
if (tableState.mode === 'history' || tableState.mode === 'persetujuan') {
|
||
selectAllCheckbox.checked = false;
|
||
selectAllCheckbox.indeterminate = false;
|
||
selectAllCheckbox.disabled = true;
|
||
return;
|
||
}
|
||
|
||
const pageIds = getSelectableIdsOnPage();
|
||
if (pageIds.length === 0) {
|
||
selectAllCheckbox.checked = false;
|
||
selectAllCheckbox.indeterminate = false;
|
||
selectAllCheckbox.disabled = true;
|
||
return;
|
||
}
|
||
|
||
selectAllCheckbox.disabled = false;
|
||
const selectedOnPage = pageIds.filter((id) => selectedIds.has(id)).length;
|
||
selectAllCheckbox.checked = selectedOnPage > 0 && selectedOnPage === pageIds.length;
|
||
selectAllCheckbox.indeterminate = selectedOnPage > 0 && selectedOnPage < pageIds.length;
|
||
}
|
||
|
||
function updateSelectionUI(){
|
||
const count = selectedIds.size;
|
||
if (selectedCountEl) selectedCountEl.textContent = String(count);
|
||
if (bulkDeleteBtn) bulkDeleteBtn.disabled = count === 0 || tableState.mode === 'history' || tableState.mode === 'persetujuan';
|
||
if (clearSelectionBtn) clearSelectionBtn.disabled = count === 0 || tableState.mode === 'history' || tableState.mode === 'persetujuan';
|
||
updateSelectAllState();
|
||
}
|
||
|
||
function approvalBadge(status, label){
|
||
if (status === 'approved') return `<span class="badge bg-success">Approved ${label}</span>`;
|
||
if (status === 'rejected') return `<span class="badge bg-danger">Rejected ${label}</span>`;
|
||
return `<span class="badge bg-warning text-dark">Pending ${label}</span>`;
|
||
}
|
||
|
||
function getPengajuanStatusBadge(item){
|
||
if (item?.status_mutu === 'rejected') {
|
||
return `<span class="badge bg-danger">Rejected Mutu</span>`;
|
||
}
|
||
if (item?.status_turt === 'rejected') {
|
||
return `<span class="badge bg-danger">Rejected TURT</span>`;
|
||
}
|
||
if (item?.status_action === 'rejected') {
|
||
return `<span class="badge bg-danger">Rejected Atasan</span>`;
|
||
}
|
||
if (item?.status_action === 'revised') {
|
||
return `<span class="badge bg-info">Revised</span>`;
|
||
}
|
||
|
||
if (item?.status_action !== 'approved') {
|
||
return `<span class="badge bg-warning text-dark">Pending Atasan</span>`;
|
||
}
|
||
|
||
const pendingApprovals = [];
|
||
if (item?.is_akre && item?.status_mutu !== 'approved') {
|
||
pendingApprovals.push('Pending Mutu');
|
||
}
|
||
if (item?.master_kategori_directory_id && item?.status_turt !== 'approved') {
|
||
pendingApprovals.push('Pending TURT');
|
||
}
|
||
|
||
if (pendingApprovals.length) {
|
||
return pendingApprovals.map((label) => `<span class="badge bg-warning text-dark">${label}</span>`).join(' ');
|
||
}
|
||
if (item?.status_action === 'approved') {
|
||
return `<span class="badge bg-success">Approved</span>`;
|
||
}
|
||
|
||
return `<span class="badge bg-warning text-dark">Pending Atasan</span>`;
|
||
}
|
||
|
||
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 isApproved = item?.status_action === 'approved';
|
||
const isRejected = item?.status_action === 'rejected' || item?.status_mutu === 'rejected' || item?.status_turt === 'rejected';
|
||
const showEdit = !isApproved || isRejected;
|
||
const showInfo = isRejected;
|
||
const id = String(item.file_directory_id);
|
||
const checked = selectedIds.has(id);
|
||
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-eye"></i>
|
||
</button>
|
||
${showInfo ? `
|
||
<button class="btn btn-sm btn-info" onclick="infoReject('${item.file_directory_id}')">
|
||
<i class="fa-solid fa-circle-info"></i>
|
||
</button>
|
||
` : ''}
|
||
${showEdit ? `
|
||
<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 class="${checked ? 'table-active' : ''}">
|
||
<td class="text-center">
|
||
<input type="checkbox"
|
||
class="form-check-input row-select"
|
||
data-id="${id}"
|
||
${checked ? 'checked' : ''}>
|
||
</td>
|
||
<td>${aksi}</td>
|
||
<td>${item.no_dokumen || '-'}</td>
|
||
<td>${getPengajuanStatusBadge(item)}</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>
|
||
${item.is_akre ? `<td colspan="2" class="text-center">Dokumen akreditasi</td>` :
|
||
`
|
||
<td>${item.name_kategori || '-'}</td>
|
||
<td>${item.name_unit || '-'}</td>
|
||
`
|
||
}
|
||
|
||
<td class="text-nowrap">${tanggalTerbit}</td>
|
||
<td class="text-nowrap">${tanggalExp}</td>
|
||
<td class="text-nowrap">${tanggal}</td>
|
||
</tr>
|
||
`;
|
||
}
|
||
|
||
function buildRowPersetujuan(item){
|
||
const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
||
const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
||
const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
||
const showMutu = isKomiteMutu && !!item.is_akre;
|
||
const showTurt = isTurt;
|
||
const actions = [
|
||
`<button type="button" 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-eye"></i></button>`
|
||
];
|
||
|
||
if (showMutu && item.status_mutu !== 'approved') {
|
||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePersetujuan('mutu','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check"></i></button>`);
|
||
actions.push(`<button class="btn btn-sm btn-danger" onclick="rejectPersetujuan('mutu','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-xmark"></i></button>`);
|
||
}
|
||
if (showTurt && item.status_turt !== 'approved') {
|
||
actions.push(`<button class="btn btn-sm btn-success" onclick="approvePersetujuan('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-check-double"></i></button>`);
|
||
actions.push(`<button class="btn btn-sm btn-danger" onclick="rejectPersetujuan('turt','${item.file_directory_id}','${item.nama_dokumen || ''}')"><i class="fa-solid fa-ban"></i></button>`);
|
||
}
|
||
if (item.status_mutu === 'rejected' && item.mutu_revision) {
|
||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectPersetujuan('Komite Mutu', ${JSON.stringify('' + (item.mutu_revision || ''))})"><i class="fa-solid fa-circle-info"></i></button>`);
|
||
}
|
||
if (item.status_turt === 'rejected' && item.turt_revision) {
|
||
actions.push(`<button class="btn btn-sm btn-info" onclick="infoRejectPersetujuan('TURT', ${JSON.stringify('' + (item.turt_revision || ''))})"><i class="fa-solid fa-circle-info"></i></button>`);
|
||
}
|
||
|
||
const statusParts = [];
|
||
if (item.is_akre) {
|
||
statusParts.push(approvalBadge(item.status_mutu, 'Mutu'));
|
||
}
|
||
if (item.master_kategori_directory_id) {
|
||
statusParts.push(approvalBadge(item.status_turt, 'TURT'));
|
||
}
|
||
|
||
return `
|
||
<tr>
|
||
<td class="text-center">-</td>
|
||
<td><div class="d-flex gap-1 flex-wrap">${actions.join('')}</div></td>
|
||
<td>${item.no_dokumen || '-'}</td>
|
||
<td><div class="d-flex gap-1 flex-wrap">${statusParts.join('')}</div></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>
|
||
${item.is_akre ? `<td colspan="2" class="text-center">Dokumen akreditasi</td>` : `<td>${item.name_kategori || '-'}</td><td>${item.name_unit || '-'}</td>`}
|
||
<td class="text-nowrap">${tanggalTerbit}</td>
|
||
<td class="text-nowrap">${tanggalExp}</td>
|
||
<td class="text-nowrap">${tanggal}</td>
|
||
</tr>
|
||
`;
|
||
}
|
||
|
||
function buildHistoryRow(item){
|
||
const tanggal = item.entry_at ? formatTanggal(item.entry_at) : '-';
|
||
const tanggalExp = item.tgl_expired ? formatTanggal(item.tgl_expired) : '-';
|
||
const tanggalTerbit = item.tanggal_terbit ? formatTanggal(item.tanggal_terbit) : '-';
|
||
const actionType = item?.action_type || '-';
|
||
return `
|
||
<tr>
|
||
<td>${item.no_dokumen || '-'}</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><span class="badge bg-info">${item.action_type}</span></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 deleteDocuments(ids, successMessage){
|
||
return fetch('/delete-file/bulk', {
|
||
method: 'DELETE',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRF-TOKEN': csrfToken
|
||
},
|
||
body: JSON.stringify({ ids })
|
||
}).then(async(res) => {
|
||
const data = await res.json();
|
||
if (!res.ok || !data?.success) {
|
||
throw new Error(data?.message || 'Gagal menghapus dokumen.');
|
||
}
|
||
|
||
ids.forEach((id) => selectedIds.delete(String(id)));
|
||
if (window.idDirectory && ids.includes(String(window.idDirectory))) {
|
||
window.idDirectory = null;
|
||
window.currentFile = null;
|
||
if (deleteDataEl) deleteDataEl.classList.add('d-none');
|
||
const modalEl = document.getElementById('previewModal');
|
||
const modalInstance = modalEl ? bootstrap.Modal.getInstance(modalEl) : null;
|
||
modalInstance?.hide();
|
||
}
|
||
|
||
Swal.fire({
|
||
icon: 'success',
|
||
title: 'Berhasil',
|
||
text: data.message || successMessage,
|
||
timer: 1500,
|
||
showConfirmButton: false
|
||
});
|
||
fetchData();
|
||
});
|
||
}
|
||
|
||
function renderPagination(totalPages){
|
||
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||
const paginationEl = tableState.mode === 'history' ? paginationHistory : paginationPengajuan;
|
||
if (!paginationEl) return;
|
||
if (totalPages <= 1) {
|
||
paginationEl.innerHTML = '';
|
||
return;
|
||
}
|
||
const maxButtons = 5;
|
||
let start = Math.max(1, activeState.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" ${activeState.page === 1 ? 'disabled' : ''}>‹</button>`;
|
||
for (let i = start; i <= end; i++) {
|
||
buttons += `<button class="btn btn-sm ${i === activeState.page ? 'btn-primary' : 'btn-outline-secondary'}" data-page="${i}">${i}</button>`;
|
||
}
|
||
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="next" ${activeState.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 ${activeState.page} dari ${totalPages}</span>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
function bindPagination(paginationEl, state){
|
||
if (!paginationEl) return;
|
||
paginationEl.addEventListener('click', (e) => {
|
||
const page = e.target.getAttribute('data-page');
|
||
if (!page) return;
|
||
if (page === 'prev' && state.page > 1) state.page--;
|
||
else if (page === 'next') {
|
||
if (state.page < state.lastPage) state.page++;
|
||
} else {
|
||
state.page = parseInt(page);
|
||
}
|
||
fetchData();
|
||
});
|
||
}
|
||
bindPagination(paginationPengajuan, tableState);
|
||
bindPagination(paginationHistory, historyState);
|
||
|
||
function renderTable(){
|
||
const isHistoryMode = tableState.mode === 'history';
|
||
const isPersetujuan = tableState.mode === 'persetujuan';
|
||
|
||
const activeState = isHistoryMode ? historyState : tableState;
|
||
|
||
const pageData = activeState.data || [];
|
||
const targetBody = isHistoryMode ? tbodyHistory : tbodyPengajuan;
|
||
const colSpan = isHistoryMode ? 9 : 11;
|
||
const rowBuilder = isHistoryMode ? buildHistoryRow : (isPersetujuan ? buildRowPersetujuan : buildRow);
|
||
if (pageData.length === 0) {
|
||
targetBody.innerHTML = `
|
||
<tr>
|
||
<td colspan="${colSpan}" class="text-center text-muted py-4">
|
||
Tidak ada data
|
||
</td>
|
||
</tr>
|
||
`;
|
||
} else {
|
||
targetBody.innerHTML = pageData.map(rowBuilder).join('');
|
||
}
|
||
|
||
const from = activeState.total === 0 ? 0 : ((activeState.page - 1) * activeState.pageSize) + 1;
|
||
const to = Math.min(((activeState.page - 1) * activeState.pageSize) + pageData.length, activeState.total);
|
||
if (summaryEl) {
|
||
summaryEl.textContent = activeState.total ? `Menampilkan ${from} - ${to} dari ${activeState.total} data` : 'Tidak ada data';
|
||
}
|
||
|
||
renderPagination(activeState.lastPage || 1);
|
||
updateSelectionUI();
|
||
}
|
||
|
||
let searchDebounce;
|
||
window.debouncedTableSearch = function(value){
|
||
clearTimeout(searchDebounce);
|
||
searchDebounce = setTimeout(() => {
|
||
const keyword = value.trim();
|
||
tableState.search = keyword;
|
||
historyState.search = keyword;
|
||
tableState.page = 1;
|
||
historyState.page = 1;
|
||
fetchData();
|
||
}, 250);
|
||
}
|
||
|
||
window.refreshLog = function(){
|
||
tableState.search = '';
|
||
tableState.startDate = '';
|
||
tableState.endDate = '';
|
||
historyState.search = '';
|
||
historyState.startDate = '';
|
||
historyState.endDate = '';
|
||
document.getElementById('tableSearch').value = '';
|
||
startDateInput.value = '';
|
||
endDateInput.value = '';
|
||
selectedIds.clear();
|
||
tableState.page = 1;
|
||
historyState.page = 1;
|
||
fetchData();
|
||
}
|
||
|
||
function updateTabUI(){
|
||
if (tabsEl) {
|
||
tabsEl.querySelectorAll('.nav-link').forEach((btn) => {
|
||
btn.classList.toggle('active', btn.getAttribute('data-mode') === tableState.mode);
|
||
});
|
||
}
|
||
if (titleEl) {
|
||
titleEl.textContent = tableState.mode === 'history'
|
||
? 'Log History'
|
||
: (tableState.mode === 'persetujuan' ? 'Data Persetujuan' : 'Data Pengajuan');
|
||
}
|
||
document.body.dataset.pengajuanMode = tableState.mode;
|
||
|
||
if (tabPengajuanEl && tabHistoryEl) {
|
||
tabPengajuanEl.classList.toggle('d-none', tableState.mode === 'history');
|
||
tabHistoryEl.classList.toggle('d-none', tableState.mode !== 'history');
|
||
}
|
||
if (bulkActionsEl) {
|
||
bulkActionsEl.classList.toggle('d-none', tableState.mode === 'history' || tableState.mode === 'persetujuan');
|
||
}
|
||
if (deleteDataEl && (tableState.mode === 'history' || tableState.mode === 'persetujuan')) {
|
||
deleteDataEl.classList.add('d-none');
|
||
}
|
||
updateSelectionUI();
|
||
}
|
||
|
||
if (tabsEl) {
|
||
tabsEl.addEventListener('click', (e) => {
|
||
const btn = e.target.closest('[data-mode]');
|
||
if (!btn) return;
|
||
const mode = btn.getAttribute('data-mode');
|
||
if (!mode || mode === tableState.mode) return;
|
||
tableState.mode = mode;
|
||
tableState.page = 1;
|
||
updateTabUI();
|
||
fetchData();
|
||
});
|
||
}
|
||
|
||
if (tbodyPengajuan) {
|
||
tbodyPengajuan.addEventListener('change', (e) => {
|
||
const target = e.target;
|
||
if (!target.classList.contains('row-select')) return;
|
||
const id = target.getAttribute('data-id');
|
||
if (!id) return;
|
||
if (target.checked) selectedIds.add(id);
|
||
else selectedIds.delete(id);
|
||
const row = target.closest('tr');
|
||
if (row) row.classList.toggle('table-active', target.checked);
|
||
updateSelectionUI();
|
||
});
|
||
}
|
||
|
||
if (selectAllCheckbox) {
|
||
selectAllCheckbox.addEventListener('change', () => {
|
||
const pageIds = getSelectableIdsOnPage();
|
||
if (selectAllCheckbox.checked) {
|
||
pageIds.forEach((id) => selectedIds.add(id));
|
||
} else {
|
||
pageIds.forEach((id) => selectedIds.delete(id));
|
||
}
|
||
renderTable();
|
||
});
|
||
}
|
||
|
||
if (clearSelectionBtn) {
|
||
clearSelectionBtn.addEventListener('click', () => {
|
||
selectedIds.clear();
|
||
renderTable();
|
||
});
|
||
}
|
||
|
||
if (bulkDeleteBtn) {
|
||
bulkDeleteBtn.addEventListener('click', () => {
|
||
if (selectedIds.size === 0) return;
|
||
const ids = Array.from(selectedIds);
|
||
Swal.fire({
|
||
title: 'Hapus dokumen terpilih?',
|
||
text: `Total ${ids.length} dokumen akan dihapus.`,
|
||
icon: 'warning',
|
||
showCancelButton: true,
|
||
confirmButtonText: 'Hapus',
|
||
cancelButtonText: 'Batal'
|
||
}).then((result) => {
|
||
if (!result.isConfirmed) return;
|
||
deleteDocuments(ids, 'Dokumen berhasil dihapus.').catch((err) => {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Gagal',
|
||
text: err.message || 'Terjadi kesalahan.'
|
||
});
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
function fetchData(){
|
||
if (summaryEl) summaryEl.textContent = 'Memuat data...';
|
||
const activeState = tableState.mode === 'history' ? historyState : tableState;
|
||
const params = new URLSearchParams({
|
||
page: activeState.page,
|
||
per_page: activeState.pageSize,
|
||
keyword: activeState.search || '',
|
||
start_date: activeState.startDate || '',
|
||
end_date: activeState.endDate || '',
|
||
mode: tableState.mode
|
||
});
|
||
const endpoint = tableState.mode === 'history'
|
||
? `/data/log-dokumen?${params.toString()}`
|
||
: `/datatable/pengajuan-file?${params.toString()}`;
|
||
fetch(endpoint)
|
||
.then(res => res.json())
|
||
.then(data => {
|
||
activeState.data = data?.data || [];
|
||
activeState.lastPage = data?.pagination?.last_page || 1;
|
||
activeState.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 notes = [];
|
||
if (item?.revision) {
|
||
notes.push(`Atasan/Bagian Terkait: ${String(item.revision)}`);
|
||
}
|
||
if (item?.mutu_revision) {
|
||
notes.push(`Komite Mutu: ${String(item.mutu_revision)}`);
|
||
}
|
||
if (item?.turt_revision) {
|
||
notes.push(`TURT: ${String(item.turt_revision)}`);
|
||
}
|
||
const revision = notes.length ? notes.join('\n\n') : 'Tidak ada catatan revisi.';
|
||
Swal.fire({
|
||
title: 'Catatan Revisi',
|
||
text: revision,
|
||
icon: 'info',
|
||
confirmButtonText: 'Tutup'
|
||
});
|
||
}
|
||
|
||
window.infoRejectPersetujuan = function(label, revision){
|
||
Swal.fire({
|
||
title: `Catatan ${label}`,
|
||
text: revision || 'Tidak ada catatan revisi.',
|
||
icon: 'info',
|
||
confirmButtonText: 'Tutup'
|
||
});
|
||
}
|
||
|
||
window.approvePersetujuan = function(type, id, fileName){
|
||
const endpoint = type === 'mutu'
|
||
? `/pengajuan-file/${id}/approve-mutu`
|
||
: `/pengajuan-file/${id}/approve-turt`;
|
||
const label = type === 'mutu' ? 'Komite Mutu' : 'TURT';
|
||
|
||
Swal.fire({
|
||
title: `Approve ${label}?`,
|
||
text: fileName || 'Dokumen akan disetujui.',
|
||
icon: 'question',
|
||
showCancelButton: true,
|
||
confirmButtonText: 'Approve',
|
||
cancelButtonText: 'Batal',
|
||
}).then((result) => {
|
||
if (!result.isConfirmed) return;
|
||
fetch(endpoint, {
|
||
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
|
||
});
|
||
fetchData();
|
||
}).catch((err) => {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Gagal',
|
||
text: err.message || 'Terjadi kesalahan.'
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
window.rejectPersetujuan = function(type, id, fileName){
|
||
const endpoint = type === 'mutu'
|
||
? `/pengajuan-file/${id}/reject-mutu`
|
||
: `/pengajuan-file/${id}/reject-turt`;
|
||
const label = type === 'mutu' ? 'Komite Mutu' : 'TURT';
|
||
|
||
Swal.fire({
|
||
title: `Reject ${label}?`,
|
||
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(endpoint, {
|
||
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
|
||
});
|
||
fetchData();
|
||
}).catch((err) => {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Gagal',
|
||
text: err.message || 'Terjadi kesalahan.'
|
||
});
|
||
});
|
||
});
|
||
}
|
||
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');
|
||
}
|
||
if (deleteDataEl) {
|
||
deleteDataEl.classList.remove('d-none');
|
||
}
|
||
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 byId(id){
|
||
return document.getElementById(id);
|
||
}
|
||
|
||
function setInputValue(el, value){
|
||
if (!el) return;
|
||
el.value = value ?? '';
|
||
}
|
||
|
||
function setTextValue(el, value){
|
||
if (!el) return;
|
||
el.textContent = value || '';
|
||
}
|
||
|
||
function setChecked(el, value){
|
||
if (!el) return;
|
||
el.checked = !!value;
|
||
}
|
||
|
||
function setSelectValue(selectEl, value, label){
|
||
if (!selectEl) return;
|
||
if (value === undefined || value === null || value === '') {
|
||
selectEl.value = '';
|
||
return;
|
||
}
|
||
const exists = Array.from(selectEl.options).some(opt => opt.value === value);
|
||
if (!exists) {
|
||
selectEl.append(new Option(label || value, value, true, true));
|
||
}
|
||
selectEl.value = value;
|
||
}
|
||
|
||
function triggerSelect2(selectEl){
|
||
if (window.$ && $.fn.select2) $(selectEl).trigger('change');
|
||
}
|
||
|
||
function formatDateForInput(date) {
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
return `${year}-${month}-${day}`;
|
||
}
|
||
|
||
function formatDateDisplay(dateValue) {
|
||
if (!dateValue) return '';
|
||
const date = new Date(`${dateValue}T00:00:00`);
|
||
if (Number.isNaN(date.getTime())) return '';
|
||
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const year = date.getFullYear();
|
||
return `${day}/${month}/${year}`;
|
||
}
|
||
|
||
function addYearsToDate(dateValue, years) {
|
||
if (!dateValue || !years) return '';
|
||
const baseDate = new Date(`${dateValue}T00:00:00`);
|
||
if (Number.isNaN(baseDate.getTime())) return '';
|
||
|
||
const originalDay = baseDate.getDate();
|
||
baseDate.setFullYear(baseDate.getFullYear() + Number(years));
|
||
if (baseDate.getDate() !== originalDay) {
|
||
baseDate.setDate(0);
|
||
}
|
||
|
||
return formatDateForInput(baseDate);
|
||
}
|
||
|
||
function syncMasaBerlakuField(selectEl) {
|
||
if (!selectEl) return;
|
||
const fieldWrap = document.getElementById(selectEl.dataset.dateTarget);
|
||
const input = document.getElementById(selectEl.dataset.inputTarget);
|
||
const preview = document.getElementById(selectEl.dataset.previewTarget);
|
||
const baseInput = document.getElementById(selectEl.dataset.baseTarget);
|
||
if (!fieldWrap || !input) return;
|
||
|
||
if (selectEl.value === 'custom') {
|
||
fieldWrap.classList.remove('d-none');
|
||
input.disabled = false;
|
||
if (preview) preview.textContent = '';
|
||
return;
|
||
}
|
||
|
||
fieldWrap.classList.add('d-none');
|
||
input.disabled = true;
|
||
input.value = '';
|
||
|
||
if (!preview) return;
|
||
if (!selectEl.value) {
|
||
preview.textContent = '';
|
||
return;
|
||
}
|
||
|
||
if (!baseInput || !baseInput.value) {
|
||
preview.textContent = 'Pilih Tanggal Terbit untuk melihat hasil masa berlaku.';
|
||
return;
|
||
}
|
||
|
||
const expiredDate = addYearsToDate(baseInput.value, selectEl.value);
|
||
preview.textContent = expiredDate ? `Tanggal kedaluwarsa: ${formatDateDisplay(expiredDate)}` : '';
|
||
}
|
||
|
||
function prepareExpiryInputs(formEl) {
|
||
const selects = formEl.querySelectorAll('.masa-berlaku-select');
|
||
for (const selectEl of selects) {
|
||
const option = selectEl.value;
|
||
const dateInput = document.getElementById(selectEl.dataset.inputTarget);
|
||
const baseInput = document.getElementById(selectEl.dataset.baseTarget);
|
||
if (!dateInput) continue;
|
||
|
||
if (!option) {
|
||
dateInput.value = '';
|
||
dateInput.disabled = true;
|
||
continue;
|
||
}
|
||
|
||
if (option === 'custom') {
|
||
if (!dateInput.value) {
|
||
return 'Tanggal kedaluwarsa wajib diisi saat memilih opsi Lainnya.';
|
||
}
|
||
dateInput.disabled = false;
|
||
continue;
|
||
}
|
||
|
||
if (!baseInput || !baseInput.value) {
|
||
return 'Tanggal Terbit wajib diisi saat memilih masa berlaku 1, 2, atau 3 tahun.';
|
||
}
|
||
|
||
dateInput.value = addYearsToDate(baseInput.value, option);
|
||
dateInput.disabled = false;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
function arrayFilterEmpty(arr){
|
||
return (arr || []).filter((val) => val !== null && val !== undefined && String(val).trim() !== '');
|
||
}
|
||
|
||
function initSelect2($el, options){
|
||
if (!$el || !$el.length || !window.$ || !$.fn.select2) return;
|
||
$el.select2(options);
|
||
}
|
||
|
||
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: String(item.id),
|
||
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;
|
||
loadEditSubUnit(String(val), null, null);
|
||
});
|
||
}
|
||
|
||
let akreData = [];
|
||
let akreLoaded = false;
|
||
let akreFlat = [];
|
||
|
||
function initEditExtraSelects(){
|
||
const akreSelect = byId('edit_akre_select');
|
||
if (akreSelect) {
|
||
loadAkreData().then(() => {
|
||
fillAkreSelect(akreSelect);
|
||
initSelect2($(akreSelect), {
|
||
dropdownParent: $('#modalEditPengajuanFile'),
|
||
placeholder: 'Pilih Instrumen',
|
||
allowClear: true
|
||
});
|
||
});
|
||
}
|
||
|
||
const editKat = $('#edit_kategori');
|
||
const editHukum = $('#edit_kategori_hukum');
|
||
initSelect2(editKat, {
|
||
dropdownParent: $('#modalEditPengajuanFile'),
|
||
placeholder: 'Pilih Kategori',
|
||
allowClear: true
|
||
});
|
||
initSelect2(editHukum, {
|
||
dropdownParent: $('#modalEditPengajuanFile'),
|
||
placeholder: 'Pilih Kategori Hukum',
|
||
allowClear: true
|
||
});
|
||
}
|
||
|
||
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 = String(unit.id);
|
||
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}"]`).length === 0) {
|
||
editSubUnitSelect.append(new Option(selectedSubName, String(selectedSubId), true, true));
|
||
}
|
||
editSubUnitSelect.trigger('change');
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function setEditAkreValue(value){
|
||
const akreEl = byId('edit_akre_select');
|
||
if (!akreEl) return;
|
||
loadAkreData().then(() => {
|
||
fillAkreSelect(akreEl);
|
||
if (value && akreValueExists(value)) {
|
||
setSelectValue(akreEl, value, value);
|
||
} else {
|
||
akreEl.value = '';
|
||
}
|
||
triggerSelect2(akreEl);
|
||
});
|
||
}
|
||
|
||
function setEditKategoriHukum(value){
|
||
const hukumEl = byId('edit_kategori_hukum');
|
||
if (!hukumEl) return;
|
||
setSelectValue(hukumEl, value, value);
|
||
triggerSelect2(hukumEl);
|
||
}
|
||
|
||
function setEditKategoriDir(item, kategoriName){
|
||
const katEl = byId('edit_kategori');
|
||
const katId = item?.master_kategori_directory_id;
|
||
if (!katEl || !katId) return;
|
||
const match = Array.from(katEl.options).find((opt) => String(opt.value).startsWith(`${katId}/`));
|
||
if (match) {
|
||
katEl.value = match.value;
|
||
} else {
|
||
const label = kategoriName || 'Kategori';
|
||
const katVal = `${katId}/${label}`;
|
||
setSelectValue(katEl, katVal, label);
|
||
}
|
||
triggerSelect2(katEl);
|
||
}
|
||
|
||
window.editFileReject = function(id){
|
||
const item = getItemById(id);
|
||
if (!item) {
|
||
Swal.fire({ icon: 'error', title: 'Gagal', text: 'Data tidak ditemukan.' });
|
||
return;
|
||
}
|
||
setInputValue(byId('edit_file_directory_id'), item.file_directory_id);
|
||
setInputValue(byId('edit_no_dokumen'), item.no_dokumen);
|
||
setInputValue(byId('edit_nama_dokumen'), item.nama_dokumen);
|
||
setInputValue(byId('edit_tanggal_terbit'), item.tanggal_terbit);
|
||
setInputValue(byId('edit_tgl_expired'), item.tgl_expired);
|
||
|
||
const isPublic = item.permission_file === true || item.permission_file === 1 || item.permission_file === '1';
|
||
setChecked(byId('edit_perm_yes'), isPublic);
|
||
setChecked(byId('edit_perm_no'), !isPublic);
|
||
|
||
const editMasaBerlaku = byId('edit_masa_berlaku_option');
|
||
if (editMasaBerlaku) {
|
||
editMasaBerlaku.value = item.tgl_expired ? 'custom' : '';
|
||
syncMasaBerlakuField(editMasaBerlaku);
|
||
}
|
||
|
||
const displayName = item.fileName || (item.file ? String(item.file).split('/').pop() : '');
|
||
setTextValue(byId('edit_current_file'), displayName ? `File saat ini: ${displayName}` : '');
|
||
|
||
const parts = arrayFilterEmpty((item.file || '').split('/'));
|
||
const unitNameFromPath = parts[0] || '';
|
||
const subNameFromPath = parts[1] || '';
|
||
const kategoriName = parts[2] || '';
|
||
const unitName = item.unit_kerja_name || item.name_unit || item.nama_unit_kerja || item.unit_name || item.unit_kerja || '';
|
||
if (editUnitSelect.length && item.id_unit_kerja) {
|
||
const unitLabel = unitName || String(item.id_unit_kerja);
|
||
const unitVal = String(item.id_unit_kerja);
|
||
setSelectValue(editUnitSelect[0], unitVal, unitLabel);
|
||
triggerSelect2(editUnitSelect[0]);
|
||
const subLabel = item.sub_unit_kerja_name || item.nama_sub_unit_kerja || item.sub_unit_name || item.sub_unit_kerja || String(item.id_sub_unit_kerja || '');
|
||
loadEditSubUnit(String(item.id_unit_kerja), item.id_sub_unit_kerja, subLabel || null);
|
||
}
|
||
|
||
setEditKategoriDir(item, kategoriName);
|
||
if (item.kategori_hukum) setEditKategoriHukum(item.kategori_hukum);
|
||
const akreFromFile = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
|
||
setEditAkreValue(item.akre || akreFromFile || '');
|
||
|
||
$("#modalEditPengajuanFile").modal('show');
|
||
}
|
||
|
||
const editMasaBerlaku = document.getElementById('edit_masa_berlaku_option');
|
||
if (editMasaBerlaku) {
|
||
editMasaBerlaku.addEventListener('change', function() {
|
||
syncMasaBerlakuField(editMasaBerlaku);
|
||
});
|
||
}
|
||
|
||
const editTanggalTerbit = document.getElementById('edit_tanggal_terbit');
|
||
if (editTanggalTerbit) {
|
||
editTanggalTerbit.addEventListener('change', function() {
|
||
if (editMasaBerlaku) syncMasaBerlakuField(editMasaBerlaku);
|
||
});
|
||
}
|
||
|
||
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 expiryError = prepareExpiryInputs(editForm);
|
||
if (expiryError) {
|
||
Swal.fire({ icon: 'warning', title: 'Validasi form', text: expiryError });
|
||
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();
|
||
initEditExtraSelects();
|
||
updateTabUI();
|
||
fetchData();
|
||
|
||
// ===== Upload baru (seperti dataUnit) =====
|
||
document.addEventListener('change', function(e){
|
||
if(!e.target.classList.contains('masa-berlaku-select')) return;
|
||
syncMasaBerlakuField(e.target);
|
||
});
|
||
|
||
document.addEventListener('change', function(e){
|
||
if (!e.target.matches('input[type="date"][id^="dateActive_"]')) return;
|
||
const index = e.target.id.replace('dateActive_', '');
|
||
const selectEl = document.querySelector(`.masa-berlaku-select[data-index="${index}"]`);
|
||
if (selectEl) syncMasaBerlakuField(selectEl);
|
||
});
|
||
|
||
function resetCreateForm(){
|
||
colCount = 1;
|
||
const colAdd = document.getElementById('col_add_fileV2');
|
||
if (colAdd) colAdd.innerHTML = '';
|
||
if (formCreate) {
|
||
formCreate.reset();
|
||
$(formCreate).find('select').val(null).trigger('change');
|
||
$(formCreate).find('input[type="file"]').val('');
|
||
$(formCreate).find('.file-name').addClass('d-none').text('');
|
||
}
|
||
document.querySelectorAll('.masa-berlaku-select').forEach(syncMasaBerlakuField);
|
||
resetAkreFields(0);
|
||
enableAkreFields(0);
|
||
}
|
||
|
||
function loadAkreData(){
|
||
if(akreLoaded) return Promise.resolve(akreData);
|
||
return fetch('/json/akreditasi.jff')
|
||
.then(res => res.json())
|
||
.then(data => {
|
||
akreData = Array.isArray(data) ? data : [];
|
||
akreFlat = [];
|
||
akreLoaded = true;
|
||
return akreData;
|
||
})
|
||
.catch(() => {
|
||
akreData = [];
|
||
akreFlat = [];
|
||
akreLoaded = true;
|
||
return akreData;
|
||
});
|
||
}
|
||
|
||
function getAkreFlat(){
|
||
if(akreFlat.length) return akreFlat;
|
||
akreFlat = (akreData || []).flatMap(type => {
|
||
const segments = Array.isArray(type.segment) ? type.segment : [];
|
||
return segments.flatMap(seg => {
|
||
const children = Array.isArray(seg.turunan) ? seg.turunan : [];
|
||
return children.map(child => ({
|
||
value: `${type.name}/${seg.name}/${child.name}`,
|
||
label: `${type.name} / ${child.name}`,
|
||
type: type.name,
|
||
segment: seg.name,
|
||
item: child.name
|
||
}));
|
||
});
|
||
});
|
||
return akreFlat;
|
||
}
|
||
|
||
function akreValueExists(value){
|
||
if (!value) return false;
|
||
return getAkreFlat().some(opt => String(opt.value) === String(value));
|
||
}
|
||
|
||
function fillAkreSelect(selectEl){
|
||
if(!selectEl) return;
|
||
selectEl.innerHTML = '<option value="">Pilih Instrumen</option>';
|
||
getAkreFlat().forEach(optData => {
|
||
const opt = document.createElement('option');
|
||
opt.value = optData.value;
|
||
opt.textContent = optData.label;
|
||
selectEl.appendChild(opt);
|
||
});
|
||
}
|
||
|
||
function setKategoriRequired(index, isRequired){
|
||
const katSelect = document.getElementById(`select_kategori_${index}`);
|
||
if (!katSelect) return;
|
||
if (isRequired) {
|
||
katSelect.setAttribute('required', 'required');
|
||
} else {
|
||
katSelect.removeAttribute('required');
|
||
}
|
||
}
|
||
|
||
function resetAkreFields(index){
|
||
const selectEl = document.getElementById(`akre_select_${index}`);
|
||
const typeInput = document.getElementById(`akre_type_${index}`);
|
||
const segmentInput = document.getElementById(`akre_segment_${index}`);
|
||
const itemInput = document.getElementById(`akre_item_${index}`);
|
||
if(selectEl){
|
||
selectEl.value = '';
|
||
if(window.$ && $.fn.select2) $(selectEl).val(null).trigger('change');
|
||
}
|
||
if(typeInput) typeInput.value = '';
|
||
if(segmentInput) segmentInput.value = '';
|
||
if(itemInput) itemInput.value = '';
|
||
setKategoriRequired(index, false);
|
||
}
|
||
|
||
function enableAkreFields(index){
|
||
const selectEl = document.getElementById(`akre_select_${index}`);
|
||
// if(selectEl){
|
||
// selectEl.disabled = false;
|
||
// selectEl.required = true;
|
||
// }
|
||
setKategoriRequired(index, false);
|
||
loadAkreData().then(() => {
|
||
fillAkreSelect(selectEl);
|
||
if(window.$ && $.fn.select2){
|
||
$(selectEl).select2({
|
||
dropdownParent: $('#modalCreateFile'),
|
||
placeholder: 'Pilih Instrumen',
|
||
allowClear:true
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
function initKategoriSelect2(index){
|
||
if(!window.$ || !$.fn.select2) return;
|
||
const katSelect = $(`#select_kategori_${index}`);
|
||
const hukumSelect = $(`#select_kategori_hukum_${index}`);
|
||
if(katSelect.length){
|
||
katSelect.select2({
|
||
dropdownParent: $('#modalCreateFile'),
|
||
placeholder:'Pilih Kategori',
|
||
allowClear:true
|
||
});
|
||
}
|
||
if(hukumSelect.length){
|
||
hukumSelect.select2({
|
||
dropdownParent: $('#modalCreateFile'),
|
||
placeholder:'Pilih Kategori Hukum',
|
||
allowClear:true
|
||
});
|
||
}
|
||
}
|
||
|
||
function selectOptionUnitKerjaV1(localCol){
|
||
const selectUnit = $(`#select_id_unit_kerja_${localCol}`);
|
||
const selectSubUnit = $(`#select_id_sub_unit_kerja_${localCol}`);
|
||
|
||
selectUnit.select2({
|
||
placeholder: '-- Pilih Unit Kerja --',
|
||
allowClear:true,
|
||
width: '100%',
|
||
dropdownParent: selectUnit.parent(),
|
||
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,
|
||
sub_units: item.sub_unit_kerja
|
||
}))
|
||
}
|
||
},
|
||
cache: true,
|
||
},
|
||
minimumInputLength: 0,
|
||
});
|
||
|
||
selectSubUnit.select2({
|
||
placeholder: '-- Pilih Sub Unit Kerja --',
|
||
allowClear: true,
|
||
width: '100%',
|
||
dropdownParent: selectSubUnit.parent()
|
||
});
|
||
|
||
selectUnit.on('select2:select', function (e) {
|
||
const data = e.params.data;
|
||
selectSubUnit.empty().append('<option value="" disabled selected>-- Pilih Sub Unit Kerja --</option>');
|
||
if (data.sub_units && data.sub_units.length > 0) {
|
||
data.sub_units.forEach(sub => {
|
||
selectSubUnit.append(`<option value="${sub.id}/${sub.name}">${sub.name}</option>`);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
window.addFormV2 = function(){
|
||
const col = document.getElementById('col_add_fileV2');
|
||
if (!col) return;
|
||
const katDok = Array.isArray(window.katDok) ? window.katDok : [];
|
||
const katOptions = katDok.map(k => `<option value="${k.master_kategori_directory_id}/${k.nama_kategori_directory}">${k.nama_kategori_directory}</option>`).join('');
|
||
|
||
let html = `
|
||
<div class="row g-3 align-items-start" id="col-${colCount}">
|
||
<hr class="my-3" />
|
||
<div class="col-12 d-flex justify-content-end">
|
||
<button type="button"
|
||
class="btn btn-sm btn-danger"
|
||
onclick="removeCol(${colCount})">
|
||
<i class="fa-solid fa-trash"></i> Hapus
|
||
</button>
|
||
</div>
|
||
|
||
<div class="col-md-6">
|
||
<label class="form-label fw-semibold">Unit <span class="text-danger">*</span></label>
|
||
<select class="form-select"
|
||
name="data[${colCount}][id_unit_kerja]"
|
||
id="select_id_unit_kerja_${colCount}"
|
||
required>
|
||
<option value="" disabled selected>Pilih Unit</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-6">
|
||
<label class="form-label fw-semibold">Sub Unit <span class="text-danger">*</span></label>
|
||
<select class="form-select"
|
||
name="data[${colCount}][id_sub_unit_kerja]"
|
||
id="select_id_sub_unit_kerja_${colCount}"
|
||
required>
|
||
<option value="" disabled selected>Pilih Sub Unit</option>
|
||
</select>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Nomor Dokumen</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text">#</span>
|
||
<input type="text"
|
||
class="form-control"
|
||
name="data[${colCount}][no_dokumen]"
|
||
placeholder="Contoh: 001/RS/IT/I/2026">
|
||
</div>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Nama Dokumen<span class="text-danger">*</span></label>
|
||
<input type="text"
|
||
class="form-control"
|
||
name="data[${colCount}][nama_dokumen]"
|
||
placeholder="Contoh: Panduan Mencuci Tangan" required>
|
||
</div>
|
||
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Tanggal Terbit</label>
|
||
<input class="form-control"
|
||
type="date"
|
||
name="data[${colCount}][date_active]"
|
||
id="dateActive_${colCount}">
|
||
</div>
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Masa Berlaku Dokumen</label>
|
||
<select class="form-select masa-berlaku-select"
|
||
name="data[${colCount}][masa_berlaku_option]"
|
||
data-index="${colCount}"
|
||
data-date-target="expiredField_${colCount}"
|
||
data-input-target="expiredInput_${colCount}"
|
||
data-base-target="dateActive_${colCount}"
|
||
data-preview-target="expiredPreview_${colCount}">
|
||
<option value="">Tidak ada</option>
|
||
<option value="1">1 Tahun</option>
|
||
<option value="2">2 Tahun</option>
|
||
<option value="3">3 Tahun</option>
|
||
<option value="custom">Lainnya</option>
|
||
</select>
|
||
<div class="form-text text-muted">Opsi 1, 2, dan 3 tahun dihitung dari Tanggal Terbit.</div>
|
||
<div class="form-text text-primary" id="expiredPreview_${colCount}"></div>
|
||
</div>
|
||
|
||
<div class="col-md-4 d-none" id="expiredField_${colCount}">
|
||
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
|
||
<input class="form-control"
|
||
type="date"
|
||
id="expiredInput_${colCount}"
|
||
name="data[${colCount}][tgl_expired]" disabled>
|
||
</div>
|
||
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Boleh dilihat unit lain? <span class="text-danger">*</span></label>
|
||
<div class="border rounded-3 p-2 bg-light">
|
||
<div class="form-check">
|
||
<input class="form-check-input"
|
||
type="radio"
|
||
name="data[${colCount}][is_permission]"
|
||
id="perm_yes_${colCount}"
|
||
value="1"
|
||
required>
|
||
<label class="form-check-label" for="perm_yes_${colCount}">Ya</label>
|
||
</div>
|
||
|
||
<div class="form-check mt-1">
|
||
<input class="form-check-input"
|
||
type="radio"
|
||
name="data[${colCount}][is_permission]"
|
||
id="perm_no_${colCount}"
|
||
value="2"
|
||
required>
|
||
<label class="form-check-label" for="perm_no_${colCount}">Tidak</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Instrumen Akreditasi </label>
|
||
<select class="form-select akre-select" id="akre_select_${colCount}" name="data[${colCount}][akre]" style="width: 350px;">
|
||
<option value="">Pilih Instrumen</option>
|
||
</select>
|
||
<div class="form-text text-muted">Isi form ini bila dokumen yang diunggah merupakan dokumen <strong>akreditasi</strong>.</div>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Kategori Hukum</label>
|
||
<select class="form-select select-kat-hukum" name="data[${colCount}][kategori_hukum]" id="select_kategori_hukum_${colCount}" style="width: 350px;">
|
||
<option value="Kebijakan - Peraturan Direktur">Kebijakan - Peraturan Direktur</option>
|
||
<option value="Kebijakan - Keputusan Direktur Utama">Kebijakan - Keputusan Direktur Utama</option>
|
||
<option value="Kebijakan - Surat Edaran">Kebijakan - Surat Edaran</option>
|
||
<option value="Kebijakan - Pengumuman">Kebijakan - Pengumuman</option>
|
||
<option value="Kerjasama - Pelayanan Kesehatan">Kerjasama - Pelayanan Kesehatan</option>
|
||
<option value="Kerjasama - Management">Kerjasama - Management</option>
|
||
<option value="Kerjasama - Pemeliharan">Kerjasama - Pemeliharan</option>
|
||
<option value="Kerjasama - Diklat">Kerjasama - Diklat</option>
|
||
<option value="Kerjasama - Luar Negeri">Kerjasama - Luar Negeri</option>
|
||
<option value="Kerjasama - Area Bisnis">Kerjasama - Area Bisnis</option>
|
||
<option value="Kerjasama - Pendidikan">Kerjasama - Pendidikan</option>
|
||
<option value="Kerjasama - Pengampuan KIA">Kerjasama- Pengampuan KIA</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<label class="form-label fw-semibold">Kategori Lainnya</label>
|
||
<select class="form-select"
|
||
name="data[${colCount}][master_kategori_directory_id]"
|
||
id="select_kategori_${colCount}" style="width: 350px;">
|
||
<option value="">Pilih Kategori</option>
|
||
${katOptions}
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-12">
|
||
<label for="fileUpload_${colCount}" class="form-label fw-semibold">📂 Upload Dokumen (PDF)</label>
|
||
<div class="border rounded-3 p-3 bg-white shadow-sm">
|
||
<input class="form-control"
|
||
type="file"
|
||
id="fileUpload_${colCount}"
|
||
accept=".pdf"
|
||
name="data[${colCount}][file]">
|
||
<div class="mt-2 text-success fw-semibold d-none file-name" id="fileName_${colCount}"></div>
|
||
</div>
|
||
<div class="form-text text-muted">Format yang didukung: <b>PDF</b>.</div>
|
||
</div>
|
||
</div>`;
|
||
col.insertAdjacentHTML('beforeend', html);
|
||
selectOptionUnitKerjaV1(colCount);
|
||
initKategoriSelect2(colCount);
|
||
enableAkreFields(colCount);
|
||
setKategoriRequired(colCount, false);
|
||
const insertedSelect = document.querySelector(`.masa-berlaku-select[data-index="${colCount}"]`);
|
||
if (insertedSelect) syncMasaBerlakuField(insertedSelect);
|
||
colCount++;
|
||
}
|
||
|
||
window.removeCol = function(count){
|
||
const el = document.getElementById(`col-${count}`);
|
||
if (el) el.remove();
|
||
}
|
||
|
||
if (formCreate) {
|
||
const select0 = $('#select_id_unit_kerja_0');
|
||
if (select0.length) selectOptionUnitKerjaV1(0);
|
||
initKategoriSelect2(0);
|
||
enableAkreFields(0);
|
||
document.querySelectorAll('.masa-berlaku-select').forEach(syncMasaBerlakuField);
|
||
|
||
formCreate.addEventListener('submit', (e) => {
|
||
e.preventDefault();
|
||
const submitBtn = formCreate.querySelector('button[type="submit"]');
|
||
if (submitBtn) submitBtn.disabled = true;
|
||
if (submitBtn) submitBtn.textContent = 'menyimpan...';
|
||
|
||
const expiryError = prepareExpiryInputs(formCreate);
|
||
if (expiryError) {
|
||
Swal.fire({ icon: 'warning', title: 'Validasi form', text: expiryError });
|
||
if (submitBtn) submitBtn.disabled = false;
|
||
if (submitBtn) submitBtn.textContent = 'Simpan';
|
||
return;
|
||
}
|
||
|
||
const formData = new FormData(formCreate);
|
||
|
||
fetch(`/uploadv2`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]')?.value || ''
|
||
},
|
||
body: formData
|
||
}).then(async(res) => {
|
||
const responseData = await res.json();
|
||
if(responseData.status){
|
||
Swal.fire({
|
||
icon: 'success',
|
||
title: 'Berhasil',
|
||
text: responseData.message || 'Data berhasil disimpan.',
|
||
timer: 1500,
|
||
showConfirmButton: false
|
||
});
|
||
const modalInstance = bootstrap.Modal.getInstance(modalCreate);
|
||
modalInstance?.hide();
|
||
resetCreateForm();
|
||
fetchData();
|
||
if(responseData.status_action === null || responseData.status_action === undefined){
|
||
Swal.fire({
|
||
icon: 'info',
|
||
title: 'Perlu Persetujuan',
|
||
text: 'Dokumen yang Anda upload butuh persetujuan dari atasan.',
|
||
confirmButtonText: 'Tutup'
|
||
});
|
||
}
|
||
} else {
|
||
throw new Error(responseData.message || 'Terjadi kesalahan saat menyimpan data.');
|
||
}
|
||
}).catch(err => {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Gagal',
|
||
text: err.message || 'Terjadi kesalahan.'
|
||
});
|
||
}).finally(() => {
|
||
if (submitBtn) submitBtn.disabled = false;
|
||
if (submitBtn) submitBtn.textContent = 'Simpan';
|
||
});
|
||
});
|
||
}
|
||
|
||
document.addEventListener('change', function(e){
|
||
if(e.target.classList.contains('akre-select')){
|
||
const id = e.target.id || '';
|
||
const idx = id.split('_').pop();
|
||
const [typeVal = '', segmentVal = '', itemVal = ''] = (e.target.value || '').split('/');
|
||
const typeInput = document.getElementById(`akre_type_${idx}`);
|
||
const segmentInput = document.getElementById(`akre_segment_${idx}`);
|
||
const itemInput = document.getElementById(`akre_item_${idx}`);
|
||
if(typeInput) typeInput.value = typeVal;
|
||
if(segmentInput) segmentInput.value = segmentVal;
|
||
if(itemInput) itemInput.value = itemVal;
|
||
return;
|
||
}
|
||
});
|
||
|
||
});
|
||
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');
|
||
}
|
||
const deleteDataEl = document.getElementById('deleteData');
|
||
if (deleteDataEl) {
|
||
deleteDataEl.classList.toggle('d-none', document.body.dataset.pengajuanMode !== 'pengajuan');
|
||
}
|
||
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');
|
||
}
|
||
|
||
if(e.target.matches('#delete-file')){
|
||
if(!idDirectory){
|
||
Swal.fire({
|
||
icon: 'warning',
|
||
title: 'Pilih dokumen',
|
||
text: 'Dokumen belum dipilih.'
|
||
});
|
||
return;
|
||
}
|
||
|
||
Swal.fire({
|
||
title: 'Hapus dokumen ini?',
|
||
text: 'Dokumen yang dihapus tidak akan tampil lagi.',
|
||
icon: 'warning',
|
||
showCancelButton: true,
|
||
confirmButtonText: 'Hapus',
|
||
cancelButtonText: 'Batal'
|
||
}).then((result) => {
|
||
if (!result.isConfirmed) return;
|
||
fetch('/delete-file/bulk', {
|
||
method: 'DELETE',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
|
||
},
|
||
body: JSON.stringify({ ids: [String(idDirectory)] })
|
||
}).then(async(res) => {
|
||
const data = await res.json();
|
||
if (!res.ok || !data?.success) {
|
||
throw new Error(data?.message || 'Gagal menghapus dokumen.');
|
||
}
|
||
Swal.fire({
|
||
icon: 'success',
|
||
title: 'Berhasil',
|
||
text: data.message || 'Dokumen berhasil dihapus.',
|
||
timer: 1500,
|
||
showConfirmButton: false
|
||
}).then(() => {
|
||
window.location.reload();
|
||
});
|
||
}).catch((err) => {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Gagal',
|
||
text: err.message || 'Terjadi kesalahan.'
|
||
});
|
||
});
|
||
});
|
||
}
|
||
})
|
||
function isPublic(permissionVal){
|
||
if(permissionVal === null || permissionVal === undefined) return false;
|
||
const val = String(permissionVal).toLowerCase();
|
||
return val === '1' || val === 'true' || val === 'ya' || val === 'yes';
|
||
}
|