985 lines
40 KiB
PHP
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.

@extends('layout.main')
<style>
/* Baris Folder */
.tree-folder {
background-color: #fcfcfc;
cursor: pointer;
transition: background 0.2s;
}
.tree-folder:hover {
background-color: #f4f7fb;
}
/* Container Indentasi */
.indent-container {
display: inline-flex;
align-items: center;
}
/* Garis Pandu Vertikal */
.tree-line {
display: inline-block;
width: 24px;
height: 40px; /* Sesuaikan dengan tinggi row */
border-left: 1px solid #e0e0e0;
margin-left: 12px;
position: relative;
}
/* Menghilangkan garis terakhir agar lebih rapi */
.tree-file:last-child .tree-line {
height: 20px;
}
/* Ikon dan Teks */
.folder-icon { color: #ffc107; font-size: 1.2rem; }
.file-icon { color: #6c757d; font-size: 1.1rem; }
.badge-pdf { background-color: #fff0f0; color: #e44d26; border: 1px solid #ffcccc; }
</style>
@section('body_main')
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-body p-3">
<div class="tab-content">
<div class="tab-pane fade show active">
<div class="d-flex justify-content-between align-items-start mb-3">
<h4 class="mb-0">Dokumen Akreditasi</h4>
<div class="d-flex align-items-start gap-3">
<div class="d-flex flex-column align-items-start">
<button
type="button"
class="btn btn-primary btn-sm"
id="btnDownloadMultiple"
disabled
>
<i class="ti ti-download me-1"></i>
Download Terpilih
</button>
<span
id="selectedCount"
class="small text-muted mt-1"
>
0 dipilih
</span>
</div>
<!-- Tambah Dokumen -->
@if(!Auth::guard('admin')->check())
<button
type="button"
class="btn btn-success btn-sm"
data-bs-toggle="modal"
data-bs-target="#modalCreateFile"
>
<i class="ti ti-plus me-1"></i>
Tambah Dokumen
</button>
@endif
</div>
</div>
<div class="d-flex flex-column flex-md-row align-items-md-center gap-2 mb-3">
<div class="d-flex flex-column flex-md-row align-items-md-center gap-2 flex-grow-1">
<input type="search" id="tableSearch" class="form-control"
placeholder="Cari Dokumen / Folder" autocomplete="off">
</div>
<div class="d-flex align-items-center gap-2">
</div>
</div>
<div class="table-responsive" style="max-height: 70vh; overflow-y:auto;">
<table class="table table-sm table-hover align-middle mb-0 table-fixed" id="lastUpdatedTable">
<thead>
<tr>
<th class="text-center" style="width: 45px;">
<input type="checkbox" id="checkAllRows" class="form-check-input">
</th>
<th style="width: 80px;">Aksi</th>
<th style="width: 40%;">Nama Dokumen / Folder</th>
<th>Tipe</th>
<th>Unit</th>
<th>Tgl Unggah</th>
</tr>
</thead>
<tbody id="tableDataAkreditasi">
<!-- data dari fetch masuk sini -->
</tbody>
</table>
</div>
<div class="d-flex flex-wrap align-items-center gap-2 mt-3">
<div class="d-flex align-items-center gap-1">
<span class="small text-muted">Tampilkan</span>
<select id="tablePageSize" class="form-select form-select-sm" style="width: 80px;">
<option value="5">5</option>
<option value="10" selected>10</option>
<option value="20">20</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
<span class="small text-muted">data</span>
</div>
<div id="paginationControls" class="ms-auto"></div>
<div class="small text-muted text-nowrap" id="tableSummary">
Memuat data...
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@include('dataUnit.modal.create')
<script>
// === STATE MANAGEMENT ===
let currentData = [];
let selectedIds = [];
let expandedFolders = new Set();
let searchTimer;
const btn = document.getElementById('btnDownloadMultiple');
const tableState = { page: 1, pageSize: 10, lastPage: 1, total: 0, from: 0, to: 0, search: '' };
const paginationEl = document.getElementById('paginationControls');
// === INITIALIZATION ===
document.addEventListener('DOMContentLoaded', () => {
fetchData();
initEventListeners();
});
// === EVENT LISTENERS ===
function initEventListeners() {
// Search dengan Debounce
document.getElementById('tableSearch').addEventListener('input', (e) => {
clearTimeout(searchTimer);
searchTimer = setTimeout(() => {
tableState.page = 1;
fetchData(e.target.value, 1);
}, 500);
});
// Per Page Change
document.getElementById('tablePageSize').addEventListener('change', (e) => {
const keyword = document.getElementById('tableSearch').value;
tableState.page = 1;
fetchData(keyword, 1);
});
// Check All Rows
document.getElementById('checkAllRows').addEventListener('change', function() {
const checkboxes = document.querySelectorAll('.row-checkbox');
selectedIds = [];
checkboxes.forEach(cb => {
cb.checked = this.checked;
if (this.checked) selectedIds.push(cb.value);
});
updateDownloadButton();
});
}
// === CORE FUNCTIONS ===
/**
* Mengambil data dari server
*/
function fetchData(keyword = '', page = 1) {
const tbody = document.getElementById('tableDataAkreditasi');
const perPage = parseInt(document.getElementById('tablePageSize').value, 10) || 10;
tableState.search = keyword;
tableState.pageSize = perPage;
tableState.page = page;
tbody.innerHTML = '<tr><td colspan="6" class="text-center">Memuat data...</td></tr>';
fetch(`/datatable-akreditasi?keyword=${encodeURIComponent(keyword)}&per_page=${perPage}&page=${page}`)
.then(res => res.json())
.then(response => {
if (response.status) {
currentData = response.data || [];
renderTable(keyword);
const pag = response.pagination || {};
tableState.total = pag.total || 0;
tableState.lastPage = pag.last_page || 1;
tableState.from = pag.from || 0;
tableState.to = pag.to || 0;
renderPagination(tableState.lastPage);
updateSummary();
} else {
tbody.innerHTML = `<tr><td colspan="6" class="text-center text-danger">${response.message}</td></tr>`;
}
})
.catch(err => {
console.error('Error fetching data:', err);
tbody.innerHTML = '<tr><td colspan="6" class="text-center text-danger">Gagal memuat data dari server.</td></tr>';
});
}
/**
* Merender tabel berdasarkan mode (Folder vs Search)
*/
function renderTable(keyword = '') {
const tbody = document.getElementById('tableDataAkreditasi');
tbody.innerHTML = '';
if (currentData.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="text-center">Tidak ada data ditemukan</td></tr>';
return;
}
// MODE 1: SEARCH VIEW (Flat View - Langsung tampilkan semua file)
if (keyword.length > 0) {
currentData.forEach(item => renderFileRow(tbody, item));
return;
}
// MODE 2: TREE VIEW (All folders & files)
const tree = buildTree(currentData);
if (expandedFolders.size === 0) {
expandAllFolders(tree, '');
}
renderTree(tbody, tree, '', 0);
}
/**
* Render Baris File (Digunakan di kedua mode)
*/
function renderFileRow(targetTbody, item) {
const fileName = item.file ? item.file.split('/').pop() : 'Unknown';
const typeDok = fileName.split('.').pop().toUpperCase();
const isChecked = selectedIds.includes(String(item.file_directory_id)) ? 'checked' : '';
targetTbody.innerHTML += `
<tr>
<td class="text-center">
<input type="checkbox" class="form-check-input row-checkbox"
value="${item.file_directory_id}" ${isChecked} onchange="handleRowCheck(this)">
</td>
<td>
<div class="btn-group">
<a href="/file-download/${item.file_directory_id}" target="_blank"
class="btn btn-sm btn-outline-primary" download title="Download">
<i class="ti ti-download"></i>
</a>
</div>
</td>
<td>
<div class="d-flex flex-column">
<strong>${item.nama_dokumen}</strong>
<small class="text-muted" style="font-size: 10px;">Path: ${item.file}</small>
</div>
</td>
<td><span class="badge bg-light text-primary border">${typeDok}</span></td>
<td></td>
<td>${item.entry_at || '-'}</td>
</tr>`;
}
// === TREE FUNCTIONS ===
function buildTree(items) {
const root = { folders: {}, files: [] };
(items || []).forEach(item => {
const path = (item.file || '').split('/').filter(Boolean);
if (path.length === 0) {
root.files.push(item);
return;
}
const fileName = path.pop();
let node = root;
path.forEach(part => {
if (!node.folders[part]) {
node.folders[part] = { folders: {}, files: [] };
}
node = node.folders[part];
});
node.files.push({ ...item, __fileName: fileName });
});
return root;
}
function expandAllFolders(node, basePath) {
Object.keys(node.folders || {}).forEach(folder => {
const folderPath = basePath ? `${basePath}/${folder}` : folder;
expandedFolders.add(folderPath);
expandAllFolders(node.folders[folder], folderPath);
});
}
function renderTree(tbody, node, basePath, level) {
const folderNames = Object.keys(node.folders || {}).sort();
folderNames.forEach(folder => {
const folderPath = basePath ? `${basePath}/${folder}` : folder;
const isExpanded = expandedFolders.has(folderPath);
const folderNode = node.folders[folder];
let lines = '';
for (let i = 0; i < level; i++) {
lines += '<span class="tree-line"></span>';
}
tbody.innerHTML += `
<tr class="tree-folder" onclick="toggleFolder('${folderPath}')">
<td></td> <td></td> <td>
<div class="indent-container">
${lines}
<span class="folder-toggle me-1">
<i class="ti ${isExpanded ? 'ti-chevron-down' : 'ti-chevron-right'} text-muted" style="font-size: 12px;"></i>
</span>
<i class="ti ti-folder-filled folder-icon me-2"></i>
<strong class="text-dark">${folder}</strong>
</div>
</td>
<td><span class="badge bg-light text-muted border-0">FOLDER</span></td>
<td class="text-muted small"></td> <td class="text-muted small"></td> </tr>
`;
if (isExpanded) {
renderTree(tbody, folderNode, folderPath, level + 1);
}
});
// Bagian ini akan memanggil renderTreeFileRow yang menampilkan tanggal
(node.files || []).forEach(item => {
renderTreeFileRow(tbody, item, level);
});
}
function getFolderMaxDate(node) {
let dates = [];
// Ambil tanggal dari file di level ini
(node.files || []).forEach(f => {
if (f.entry_at) dates.push(new Date(f.entry_at));
});
// Ambil tanggal dari sub-folder (rekursif)
Object.values(node.folders || {}).forEach(subNode => {
const subDate = getFolderMaxDate(subNode);
if (subDate) dates.push(new Date(subDate));
});
if (dates.length === 0) return null;
// Cari tanggal paling besar (terbaru)
const maxDate = new Date(Math.max(...dates));
// Format balik ke YYYY-MM-DD
return maxDate.toISOString().split('T')[0];
}
function renderTreeFileRow(targetTbody, item, level){
const fileName = item.__fileName || (item.file ? item.file.split('/').pop() : 'Unknown');
const typeDok = fileName.split('.').pop().toUpperCase();
const isChecked = selectedIds.includes(String(item.file_directory_id)) ? 'checked' : '';
let lines = '';
for (let i = 0; i < level; i++) {
lines += '<span class="tree-line"></span>';
}
targetTbody.innerHTML += `
<tr class="tree-file">
<td class="text-center">
<input type="checkbox" class="form-check-input row-checkbox"
value="${item.file_directory_id}" ${isChecked} onchange="handleRowCheck(this)">
</td>
<td>
<a href="/file-download/${item.file_directory_id}" target="_blank"
class="btn btn-sm btn-primary text-white border">
<i class="ti ti-download"></i>
</a>
</td>
<td>
<div class="indent-container">
${lines}
<span style="width: 24px;"></span> <i class="ti ti-file-text file-icon me-2"></i>
<div class="d-flex flex-column">
<span class="text-dark fw-medium">${item.nama_dokumen}</span>
<small class="text-muted" style="font-size: 10px;">${fileName}</small>
</div>
</div>
</td>
<td><span class="badge bg-danger">${typeDok}</span></td>
<td>${item.unit?.name || '-'}</td>
<td class="text-muted small">${formatDateTime(item.entry_at)}</td>
</tr>`;
}
// Tambahkan fungsi ini di dalam <script>
function toggleFolder(folderPath) {
if (expandedFolders.has(folderPath)) {
expandedFolders.delete(folderPath);
} else {
expandedFolders.add(folderPath);
}
renderTable(document.getElementById('tableSearch').value || '');
}
// === UTILITY FUNCTIONS ===
function handleRowCheck(checkbox) {
const val = String(checkbox.value);
if (checkbox.checked) {
if (!selectedIds.includes(val)) selectedIds.push(val);
} else {
selectedIds = selectedIds.filter(id => id !== val);
document.getElementById('checkAllRows').checked = false;
}
updateDownloadButton();
}
function updateDownloadButton() {
const countLabel = document.getElementById('selectedCount');
btn.disabled = selectedIds.length === 0;
countLabel.innerText = `${selectedIds.length} dipilih`;
}
function updateSummary() {
const summary = document.getElementById('tableSummary');
if (!summary) return;
if (!tableState.total) {
summary.innerText = 'Tidak ada data';
return;
}
const from = tableState.from || 0;
const to = tableState.to || 0;
summary.innerText = `Menampilkan ${from} - ${to} dari ${tableState.total} data`;
}
function renderPagination(totalPages){
if(!paginationEl) return;
if(totalPages <= 1){
paginationEl.innerHTML = '';
return;
}
const maxButtons = 5;
let start = Math.max(1, tableState.page - Math.floor(maxButtons/2));
let end = Math.min(totalPages, start + maxButtons - 1);
start = Math.max(1, end - maxButtons + 1);
let buttons = '';
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="prev" ${tableState.page === 1 ? 'disabled' : ''}> Sebelumnya</button>`;
for(let i=start; i<=end; i++){
buttons += `<button class="btn btn-sm ${i === tableState.page ? 'btn-primary' : 'btn-outline-secondary'}" data-page="${i}">${i}</button>`;
}
buttons += `<button class="btn btn-outline-secondary btn-sm" data-page="next" ${tableState.page === totalPages ? 'disabled' : ''}>Berikutnya </button>`;
paginationEl.innerHTML = `
<div class="d-flex align-items-center gap-2 flex-wrap">
<div class="btn-group" role="group">${buttons}</div>
<span class="small text-muted">Halaman ${tableState.page} dari ${totalPages}</span>
</div>
`;
}
if(paginationEl){
paginationEl.addEventListener('click', (e) => {
const page = e.target.getAttribute('data-page');
if(!page) return;
if(page === 'prev' && tableState.page > 1) tableState.page--;
else if(page === 'next'){
if(tableState.page < tableState.lastPage) tableState.page++;
}else{
tableState.page = parseInt(page, 10) || 1;
}
fetchData(tableState.search || '', tableState.page);
});
}
const downloadBtn = document.getElementById('btnDownloadMultiple');
if (downloadBtn) {
downloadBtn.addEventListener('click', function(){
if(selectedIds.length === 0){
return;
}
const payload = { ids: Array.from(selectedIds) };
downloadBtn.disabled = true;
downloadBtn.textContent = 'Menyiapkan...';
fetch('/download-multiple', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify(payload)
})
.then(async (res) => {
const contentType = res.headers.get('content-type') || '';
if(!res.ok || contentType.includes('application/json')){
const err = await res.json().catch(() => ({}));
throw new Error(err?.message || 'Gagal download file');
}
const blob = await res.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
const disposition = res.headers.get('content-disposition') || '';
const match = disposition.match(/filename="?([^"]+)"?/);
a.href = url;
a.download = match?.[1] || 'files.zip';
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
})
.catch(err => {
Swal.fire({ icon: 'error', title: 'Gagal', text: err.message || 'Gagal download file' });
})
.finally(() => {
downloadBtn.disabled = selectedIds.length === 0;
downloadBtn.textContent = 'Download Terpilih';
});
});
}
document.addEventListener('click', function(e){
const toggle = e.target.closest('.folder-toggle');
if (!toggle) return;
const folderPath = toggle.getAttribute('data-folder');
if (!folderPath) return;
if (expandedFolders.has(folderPath)) {
expandedFolders.delete(folderPath);
} else {
expandedFolders.add(folderPath);
}
renderTable(document.getElementById('tableSearch').value || '');
});
function formatDateTime(value) {
if (!value) return '—';
const d = new Date(value);
if (isNaN(d)) return value;
const pad = n => String(n).padStart(2, '0');
return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} `
+ `${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
const katDok = @json($katDok);
const formCreate = document.getElementById('formFile');
const modalCreate = document.getElementById('modalCreateFile');
let colCount = 1;
document.addEventListener('change', function(e){
if(!e.target.classList.contains('toggle-expired')) return;
const targetId = e.target.getAttribute('data-target');
if(!targetId) return;
const fieldWrap = document.getElementById(targetId);
const input = fieldWrap?.querySelector('input');
if (input) input.disabled = !e.target.checked;
});
let akreData = [];
let akreLoaded = false;
let akreFlat = [];
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 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}`);
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 katOptions = (Array.isArray(katDok) ? 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]">
</div>
<div class="col-md-3">
<div class="form-check">
<input class="form-check-input toggle-expired"
type="checkbox"
id="hasExpired_${colCount}"
data-target="expiredField_${colCount}">
<label class="form-check-label" for="hasExpired_${colCount}">Masa Berlaku Dokumen?</label>
</div>
</div>
<div class="col-md-5" id="expiredField_${colCount}">
<label class="form-label fw-semibold">Tanggal Kedaluwarsa Dokumen</label>
<input class="form-control"
type="date"
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="">Pilih Kategori Hukum</option>
<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);
colCount++;
}
window.removeCol = function(count){
const el = document.getElementById(`col-${count}`);
if (el) el.remove();
}
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('');
}
resetAkreFields(0);
enableAkreFields(0);
}
if (formCreate) {
const select0 = $('#select_id_unit_kerja_0');
if (select0.length) selectOptionUnitKerjaV1(0);
initKategoriSelect2(0);
enableAkreFields(0);
formCreate.addEventListener('submit', (e) => {
e.preventDefault();
const submitBtn = formCreate.querySelector('button[type="submit"]');
if (submitBtn) submitBtn.disabled = true;
if (submitBtn) submitBtn.textContent = 'menyimpan...';
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();
} 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;
}
});
</script>
@endsection