1793 lines
73 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: '', 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 pendingPersetujuanNotice = document.getElementById('pendingPersetujuanNotice');
const pendingPersetujuanNoticeCount = document.getElementById('pendingPersetujuanNoticeCount');
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;
const isAtasan = !!window.isAtasan;
let editFromQueryId = new URLSearchParams(window.location.search).get('edit');
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){
const normalized = String(status || '').toLowerCase();
if (normalized === 'approved') return `<span class="badge bg-success">Approved ${label}</span>`;
if (normalized.startsWith('rejected')) return `<span class="badge bg-danger">Rejected ${label}</span>`;
if (normalized.startsWith('revised')) return `<span class="badge bg-info">Revised ${label}</span>`;
return `<span class="badge bg-warning text-dark">Pending ${label}</span>`;
}
function hasRevisionInfo(item){
return !!(item?.revision || item?.mutu_revision || item?.turt_revision);
}
function collectRevisionNotes(item){
const notes = [];
const genericRevision = String(item?.revision || '').trim();
const mutuRevision = String(item?.mutu_revision || '').trim();
const turtRevision = String(item?.turt_revision || '').trim();
if (genericRevision) {
const lowerGeneric = genericRevision.toLowerCase();
if (!lowerGeneric.startsWith('komite mutu:') && !lowerGeneric.startsWith('turt:')) {
notes.push({ label: 'Atasan/Bagian Terkait', text: genericRevision });
}
}
if (mutuRevision) {
notes.push({ label: 'Komite Mutu', text: mutuRevision });
}
if (turtRevision) {
notes.push({ label: 'TURT', text: turtRevision });
}
return notes;
}
function escapeHtml(value){
return String(value ?? '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function buildRevisionNotesHtml(notes){
if (!notes.length) {
return '<div class="text-muted">Tidak ada catatan revisi.</div>';
}
return `
<div class="text-start" style="line-height:1.6;">
${notes.map(note => `
<div class="mb-2">
<div><strong>${escapeHtml(note.label)}</strong></div>
<div>${escapeHtml(note.text)}</div>
</div>
`).join('')}
</div>
`;
}
function isRejectedStatus(item){
return String(item?.status_action || '').toLowerCase().startsWith('rejected')
|| String(item?.status_mutu || '').toLowerCase().startsWith('rejected')
|| String(item?.status_turt || '').toLowerCase().startsWith('rejected');
}
function isApprovedStatus(status){
return String(status || '').toLowerCase() === 'approved';
}
function canProcessRoleStatus(status){
const normalized = String(status || '').toLowerCase();
return normalized === '' || normalized.startsWith('revised');
}
function getPengajuanStatusBadges(item){
const actionStatus = String(item?.status_action || '').toLowerCase();
const mutuStatus = String(item?.status_mutu || '').toLowerCase();
const turtStatus = String(item?.status_turt || '').toLowerCase();
if (actionStatus.startsWith('revised')) {
return `<span class="badge bg-info">Revised</span>`;
}
if (actionStatus.startsWith('rejected')) {
return `<span class="badge bg-danger">Rejected Atasan</span>`;
}
if (actionStatus !== 'approved') {
return `<span class="badge bg-warning text-dark">Pending Atasan</span>`;
}
const statuses = [];
if (item?.is_akre) {
if (mutuStatus.startsWith('rejected mutu')) {
statuses.push(`<span class="badge bg-danger">Rejected Mutu</span>`);
} else if (mutuStatus === 'revised mutu') {
statuses.push(`<span class="badge bg-info text-white">Revisi Mutu</span>`);
} else if(mutuStatus === 'approved'){
statuses.push(`<span class="badge bg-success text-white">Approved Mutu</span>`);
}else{
statuses.push(`<span class="badge bg-warning text-dark">Pending Mutu</span>`);
}
}
if (item?.master_kategori_directory_id) {
if (turtStatus.startsWith('rejected turt')) {
statuses.push(`<span class="badge bg-danger">Rejected TURT</span>`);
} else if (turtStatus === 'revised turt') {
statuses.push(`<span class="badge bg-info text-white">Revisi TURT</span>`);
} else if(turtStatus === 'approved'){
statuses.push(`<span class="badge bg-success text-white">Approved TURT</span>`);
} else{
statuses.push(`<span class="badge bg-warning text-dark">Pending TURT</span>`);
}
}
if (statuses.length > 0) {
return statuses.join(' ');
}
return `<span class="badge bg-success">Approved</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 = isApprovedStatus(item?.status_action);
const isRejected = isRejectedStatus(item);
const showEdit = isRejected;
const showInfo = isRejected && hasRevisionInfo(item);
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><div class="d-flex gap-1 flex-wrap">${getPengajuanStatusBadges(item)}</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>
<td class="">${item.kategori}</td>
<td class="text-nowrap">${item.nama_unit}</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 && canProcessRoleStatus(item.status_mutu)) {
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 && canProcessRoleStatus(item.status_turt)) {
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"></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 (hasRevisionInfo(item)) {
actions.push(`<button class="btn btn-sm btn-info" onclick="infoReject('${item.file_directory_id}')"><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 class="text-center align-middle"><div class="d-flex justify-content-center gap-1 flex-nowrap">${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>
<td>${item?.kategori}</td>
<td>${item?.nama_unit}</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.kategori || '-'}</td>
<td>${item.nama_unit || '-'}</td>
<td><span class="badge bg-info">${item.action_type}</span></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();
maybeOpenEditFromQuery();
}
function maybeOpenEditFromQuery(){
if (!editFromQueryId || tableState.mode !== 'pengajuan') return;
const item = getItemById(editFromQueryId);
if (!item) return;
const cleanUrl = new URL(window.location.href);
cleanUrl.searchParams.delete('edit');
window.history.replaceState({}, '', cleanUrl.toString());
const pendingId = editFromQueryId;
editFromQueryId = null;
window.editFileReject(pendingId);
}
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();
}
function updatePendingPersetujuanIndicators(total){
const count = Number(total || 0);
console.log(pendingPersetujuanNoticeCount);
if (pendingPersetujuanNotice && pendingPersetujuanNoticeCount) {
pendingPersetujuanNoticeCount.textContent = String(count);
pendingPersetujuanNotice.classList.toggle('d-none', count <= 0);
pendingPersetujuanNotice.classList.toggle('d-flex', count > 0);
}
}
function fetchPendingPersetujuanCount(){
if (!(isKomiteMutu || isTurt || isAtasan)) return;
fetch('/data/count-pending', {
headers: {
'Accept': 'application/json'
}
})
.then(res => res.json())
.then(data => {
updatePendingPersetujuanIndicators(data?.count || 0);
})
.catch(() => {
updatePendingPersetujuanIndicators(0);
});
}
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();
fetchPendingPersetujuanCount();
})
.catch(err => {
console.error(err);
if (summaryEl) summaryEl.textContent = 'Gagal memuat data';
});
}
window.infoReject = function(id){
const item = getItemById(id);
Swal.fire({
title: 'Catatan Revisi',
html: buildRevisionNotesHtml(collectRevisionNotes(item)),
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
});
if (typeof window.refreshPendingCount === 'function') window.refreshPendingCount();
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
});
if (typeof window.refreshPendingCount === 'function') window.refreshPendingCount();
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');
if (typeof window.refreshPendingCount === 'function') window.refreshPendingCount();
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();
if (typeof window.refreshPendingCount === 'function') window.refreshPendingCount();
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';
}