739 lines
25 KiB
PHP
739 lines
25 KiB
PHP
<style>
|
|
|
|
.message-body {
|
|
max-height: 360px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
|
|
.message-body .dropdown-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 1px;
|
|
}
|
|
.message-body .dropdown-item div {
|
|
white-space: normal;
|
|
word-break: break-word;
|
|
}
|
|
.message-body .dropdown-item:hover {
|
|
background-color: #f0f2f5;
|
|
}
|
|
|
|
/* DOT */
|
|
.nav-link {
|
|
position: relative;
|
|
}
|
|
|
|
.notif-dot {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
width: 10px;
|
|
height: 10px;
|
|
background-color: red;
|
|
border-radius: 50%;
|
|
z-index: 10;
|
|
animation: pulse 1.5s infinite;
|
|
}
|
|
|
|
#expiredDot {
|
|
background-color: orange;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0% { transform: scale(1); opacity: 1; }
|
|
50% { transform: scale(1.5); opacity: 0.6; }
|
|
100% { transform: scale(1); opacity: 1; }
|
|
}
|
|
</style>
|
|
|
|
<header class="app-header">
|
|
<nav class="navbar navbar-expand-lg navbar-light">
|
|
<ul class="navbar-nav">
|
|
<li class="nav-item d-block d-xl-none">
|
|
<a class="nav-link sidebartoggler " id="headerCollapse" href="javascript:void(0)">
|
|
<i class="ti ti-menu-2"></i>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
<div class="navbar-collapse justify-content-end px-0" id="navbarNav">
|
|
<ul class="navbar-nav flex-row ms-auto align-items-center justify-content-end">
|
|
<li class="nav-item dropdown">
|
|
<a class="nav-link position-relative" href="javascript:void(0)" id="dropExpired" data-bs-toggle="dropdown" aria-expanded="false">
|
|
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-light" style="width:46px;height:46px;">
|
|
<i class="ti ti-alert-circle text-primary"></i>
|
|
</span>
|
|
<span id="expiredDot" class="notif-dot d-none">
|
|
</span>
|
|
</a>
|
|
<div class="dropdown-menu dropdown-menu-end dropdown-menu-animate-up shadow" aria-labelledby="dropExpired" style="min-width: 320px;">
|
|
<div class="d-flex align-items-center justify-content-between px-3 border-bottom">
|
|
<span class="fw-semibold">Notifikasi Expired</span>
|
|
<button type="button" class="btn btn-sm btn-outline-primary my-2" id="expiredOpenDetailBtn">
|
|
Detail
|
|
</button>
|
|
</div>
|
|
<div class="message-body" id="expiredNotifList">
|
|
<div class="dropdown-item text-muted small">Memuat...</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li class="nav-item dropdown">
|
|
<a class="nav-link position-relative" href="javascript:void(0)" id="dropNotif" data-bs-toggle="dropdown" aria-expanded="false">
|
|
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-light" style="width:46px;height:46px;">
|
|
<i class="ti ti-bell text-primary"></i>
|
|
</span>
|
|
<span id="notifCountBadge" class="position-absolute top-0 start-50 badge rounded-pill bg-danger d-none">
|
|
0
|
|
</span>
|
|
</a>
|
|
<div class="dropdown-menu dropdown-menu-end dropdown-menu-animate-up shadow" aria-labelledby="dropNotif" style="min-width: 320px;">
|
|
<div class="d-flex align-items-center justify-content-between px-3 border-bottom">
|
|
<span class="fw-semibold">Notifikasi</span>
|
|
<span class="small text-muted" id="notifCountText">0 baru</span>
|
|
</div>
|
|
<div class="message-body" id="notifList">
|
|
<div class="dropdown-item text-muted small">Memuat...</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
|
|
<li class="nav-item dropdown">
|
|
<a class="nav-link " href="javascript:void(0)" id="drop2" data-bs-toggle="dropdown"
|
|
aria-expanded="false">
|
|
<img src="./assets/images/profile/user-1.jpg" alt="" width="35" height="35" class="rounded-circle">
|
|
</a>
|
|
<div class="dropdown-menu dropdown-menu-end dropdown-menu-animate-up" aria-labelledby="drop2">
|
|
<div class="message-body">
|
|
<a href="javascript:void(0)" class="d-flex align-items-center gap-2 dropdown-item">
|
|
<i class="ti ti-user fs-6"></i>
|
|
<p class="mb-0 fs-3">{{ auth()->user()->namauser ?? 'admin' }}</p>
|
|
</a>
|
|
<form action="/logout" method="POST">
|
|
@csrf
|
|
<button type="submit" class="btn btn-outline-primary mx-3 mt-2 d-block">Logout</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<!-- Modal: Detail Dokumen Akan Expired -->
|
|
<div class="modal fade" id="expiredDetailModal" tabindex="-1" aria-labelledby="expiredDetailModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="expiredDetailModalLabel">Detail Notifikasi Dokumen Akan Expired</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row g-2 align-items-end mb-3">
|
|
<div class="col-12 col-md-4">
|
|
<label class="form-label mb-1">Akan expired ≤ (hari)</label>
|
|
<input type="number" class="form-control" id="expiredFilterDaysMax" min="0" step="1" value="30">
|
|
</div>
|
|
<div class="col-12 col-md-4 d-flex gap-2">
|
|
<button type="button" class="btn btn-primary flex-grow-1" id="expiredApplyFilterBtn">Terapkan</button>
|
|
<button type="button" class="btn btn-outline-secondary" id="expiredResetFilterBtn">Reset</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex align-items-center justify-content-between mb-2">
|
|
<div class="small text-muted" id="expiredDetailInfo">-</div>
|
|
<div class="d-flex align-items-center gap-2">
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="expiredDetailPrevBtn">Prev</button>
|
|
<span class="small" id="expiredDetailPageText">1</span>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="expiredDetailNextBtn">Next</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-sm table-striped align-middle mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th style="width: 56px;">#</th>
|
|
<th>Unit</th>
|
|
<th>No Dokumen</th>
|
|
<th>Nama Dokumen</th>
|
|
<th style="width: 140px;">Tgl Expired</th>
|
|
<th style="width: 140px;">Sisa (hari)</th>
|
|
<th style="width: 140px;">Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="expiredDetailTbody">
|
|
<tr>
|
|
<td colspan="7" class="text-muted small">Memuat...</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Tutup</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| HELPER
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
function escapeHtml(value) {
|
|
return String(value ?? '')
|
|
.replaceAll('&', '&')
|
|
.replaceAll('<', '<')
|
|
.replaceAll('>', '>')
|
|
.replaceAll('"', '"')
|
|
.replaceAll("'", ''');
|
|
}
|
|
|
|
function ajaxGet(url) {
|
|
return fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
}
|
|
|
|
function ajaxPost(url) {
|
|
return fetch(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRF-TOKEN': csrfToken,
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| NOTIFIKASI BIASA
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
const notifListEl = document.getElementById('notifList');
|
|
const notifCountTextEl = document.getElementById('notifCountText');
|
|
const notifBadgeEl = document.getElementById('notifCountBadge');
|
|
const notifToggle = document.getElementById('dropNotif') || document.getElementById('drop1');
|
|
|
|
function setNotifList(items) {
|
|
if (!notifListEl) return;
|
|
|
|
if (!items || !items.length) {
|
|
notifListEl.innerHTML = `
|
|
<div class="dropdown-item text-muted small">
|
|
Tidak ada notifikasi
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
notifListEl.innerHTML = items.map(item => {
|
|
const url = item.url || '#';
|
|
const text = escapeHtml(item.text_notifikasi || '-');
|
|
const createdAt = escapeHtml(item.created_at || '');
|
|
const isRead = item.is_read ? true : false;
|
|
|
|
return `
|
|
<a href="${url}" class="dropdown-item d-flex align-items-start gap-2">
|
|
<span class="badge ${isRead ? 'bg-secondary' : 'bg-primary'} rounded-circle"
|
|
style="width:10px;height:10px;margin-top:6px;"></span>
|
|
<div>
|
|
<div class="fw-semibold">${text}</div>
|
|
<div class="small text-muted">${createdAt}</div>
|
|
</div>
|
|
</a>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
function setNotifBadge(unread) {
|
|
unread = Number(unread || 0);
|
|
|
|
if (notifCountTextEl) {
|
|
notifCountTextEl.textContent = `${unread} baru`;
|
|
}
|
|
|
|
if (!notifBadgeEl) return;
|
|
|
|
if (unread > 0) {
|
|
notifBadgeEl.classList.remove('d-none');
|
|
notifBadgeEl.textContent = unread > 99 ? '99+' : unread;
|
|
} else {
|
|
notifBadgeEl.classList.add('d-none');
|
|
notifBadgeEl.textContent = '0';
|
|
}
|
|
}
|
|
|
|
function loadNotifications() {
|
|
ajaxGet('/data/notifications')
|
|
.then(r => r.json())
|
|
.then(res => {
|
|
const unread = res?.status ? Number(res.unread || 0) : 0;
|
|
const items = res?.status ? (res.data || []) : [];
|
|
|
|
setNotifBadge(unread);
|
|
setNotifList(items);
|
|
})
|
|
.catch(() => {
|
|
if (notifListEl) {
|
|
notifListEl.innerHTML = `
|
|
<div class="dropdown-item text-muted small">
|
|
Gagal memuat notifikasi
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
setNotifBadge(0);
|
|
});
|
|
}
|
|
|
|
function markNotificationsAsRead() {
|
|
ajaxPost('/data/notifications/read')
|
|
.then(() => {
|
|
setNotifBadge(0);
|
|
|
|
if (notifListEl) {
|
|
notifListEl.querySelectorAll('.badge').forEach(badge => {
|
|
badge.classList.remove('bg-primary');
|
|
badge.classList.add('bg-secondary');
|
|
});
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
|
|
if (notifToggle) {
|
|
notifToggle.addEventListener('show.bs.dropdown', function() {
|
|
markNotificationsAsRead();
|
|
});
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| NOTIFIKASI EXPIRED
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
const expiredListEl = document.getElementById('expiredNotifList');
|
|
const expiredDotEl = document.getElementById('expiredDot');
|
|
const expiredToggle = document.getElementById('dropExpired');
|
|
|
|
function setExpiredList(items) {
|
|
if (!expiredListEl) return;
|
|
|
|
if (!items || !items.length) {
|
|
expiredListEl.innerHTML = `
|
|
<div class="dropdown-item text-muted small">
|
|
Tidak ada notifikasi expired
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
expiredListEl.innerHTML = items.map(item => {
|
|
const url = item.url || '#';
|
|
const text = escapeHtml(item.text_notifikasi || '-');
|
|
const createdAt = escapeHtml(item.created_at || '');
|
|
const isRead = item.is_read ? true : false;
|
|
|
|
const docId = item.doc_id || item.document_id || item.dokumen_id || item.id || '';
|
|
|
|
return `
|
|
<a href="${url}"
|
|
class="dropdown-item d-flex align-items-start gap-2 js-expired-notif-item"
|
|
data-doc-id="${docId}">
|
|
<span class="badge ${isRead ? 'bg-secondary' : 'bg-warning'} rounded-circle"
|
|
style="width:10px;height:10px;margin-top:6px;"></span>
|
|
<div>
|
|
<div class="fw-semibold">${text}</div>
|
|
<div class="small text-muted">${createdAt}</div>
|
|
</div>
|
|
</a>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
function setExpiredDot(unread) {
|
|
unread = Number(unread || 0);
|
|
|
|
if (!expiredDotEl) return;
|
|
|
|
if (unread > 0) {
|
|
expiredDotEl.classList.remove('d-none');
|
|
} else {
|
|
expiredDotEl.classList.add('d-none');
|
|
}
|
|
}
|
|
|
|
function loadExpiredNotifications() {
|
|
ajaxGet('/data/expired-notifications')
|
|
.then(r => r.json())
|
|
.then(res => {
|
|
const unread = res?.status ? Number(res.unread || 0) : 0;
|
|
const items = res?.status ? (res.data || []) : [];
|
|
|
|
setExpiredDot(unread);
|
|
setExpiredList(items);
|
|
})
|
|
.catch(() => {
|
|
if (expiredListEl) {
|
|
expiredListEl.innerHTML = `
|
|
<div class="dropdown-item text-muted small">
|
|
Gagal memuat notifikasi expired
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
setExpiredDot(0);
|
|
});
|
|
}
|
|
|
|
function markExpiredNotificationsAsRead() {
|
|
ajaxPost('/data/expired-notifications/read')
|
|
.then(() => {
|
|
setExpiredDot(0);
|
|
|
|
if (expiredListEl) {
|
|
expiredListEl.querySelectorAll('.badge').forEach(badge => {
|
|
badge.classList.remove('bg-warning');
|
|
badge.classList.add('bg-secondary');
|
|
});
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
|
|
if (expiredToggle) {
|
|
expiredToggle.addEventListener('show.bs.dropdown', function() {
|
|
markExpiredNotificationsAsRead();
|
|
});
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| MODAL DETAIL EXPIRED
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
const expiredDetailModalEl = document.getElementById('expiredDetailModal');
|
|
|
|
let expiredDetailModal = null;
|
|
|
|
if (expiredDetailModalEl && window.bootstrap && window.bootstrap.Modal) {
|
|
expiredDetailModal = new bootstrap.Modal(expiredDetailModalEl);
|
|
}
|
|
|
|
const expiredState = {
|
|
docId: null,
|
|
page: 1,
|
|
perPage: 10
|
|
};
|
|
|
|
const expiredDetailTbody = document.getElementById('expiredDetailTbody');
|
|
const expiredDetailInfo = document.getElementById('expiredDetailInfo');
|
|
const expiredDetailPageText = document.getElementById('expiredDetailPageText');
|
|
|
|
const expiredOpenDetailBtn = document.getElementById('expiredOpenDetailBtn');
|
|
const expiredFilterDaysMax = document.getElementById('expiredFilterDaysMax');
|
|
const expiredApplyFilterBtn = document.getElementById('expiredApplyFilterBtn');
|
|
const expiredResetFilterBtn = document.getElementById('expiredResetFilterBtn');
|
|
const expiredDetailPrevBtn = document.getElementById('expiredDetailPrevBtn');
|
|
const expiredDetailNextBtn = document.getElementById('expiredDetailNextBtn');
|
|
|
|
function showExpiredModal() {
|
|
if (expiredDetailModal) {
|
|
expiredDetailModal.show();
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Fallback kalau bootstrap.Modal tidak terbaca.
|
|
* Ini berguna kalau Bootstrap JS belum include.
|
|
*/
|
|
if (expiredDetailModalEl) {
|
|
expiredDetailModalEl.classList.add('show');
|
|
expiredDetailModalEl.style.display = 'block';
|
|
expiredDetailModalEl.removeAttribute('aria-hidden');
|
|
expiredDetailModalEl.setAttribute('aria-modal', 'true');
|
|
|
|
document.body.classList.add('modal-open');
|
|
|
|
let backdrop = document.createElement('div');
|
|
backdrop.className = 'modal-backdrop fade show';
|
|
backdrop.id = 'manualExpiredBackdrop';
|
|
document.body.appendChild(backdrop);
|
|
} else {
|
|
alert('Modal expiredDetailModal tidak ditemukan di HTML.');
|
|
}
|
|
}
|
|
|
|
function hideExpiredModalFallback() {
|
|
if (!expiredDetailModalEl) return;
|
|
|
|
expiredDetailModalEl.classList.remove('show');
|
|
expiredDetailModalEl.style.display = 'none';
|
|
expiredDetailModalEl.setAttribute('aria-hidden', 'true');
|
|
expiredDetailModalEl.removeAttribute('aria-modal');
|
|
|
|
document.body.classList.remove('modal-open');
|
|
|
|
const backdrop = document.getElementById('manualExpiredBackdrop');
|
|
if (backdrop) {
|
|
backdrop.remove();
|
|
}
|
|
}
|
|
|
|
expiredDetailModalEl?.querySelectorAll('[data-bs-dismiss="modal"]').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
if (!expiredDetailModal) {
|
|
hideExpiredModalFallback();
|
|
}
|
|
});
|
|
});
|
|
|
|
function setExpiredDetailLoading(text = 'Memuat...') {
|
|
if (!expiredDetailTbody) return;
|
|
|
|
expiredDetailTbody.innerHTML = `
|
|
<tr>
|
|
<td colspan="7" class="text-muted small">${escapeHtml(text)}</td>
|
|
</tr>
|
|
`;
|
|
}
|
|
|
|
function buildExpiredDetailParams() {
|
|
const params = new URLSearchParams();
|
|
|
|
params.set('page', String(expiredState.page));
|
|
params.set('per_page', String(expiredState.perPage));
|
|
|
|
if (expiredState.docId) {
|
|
params.set('doc_id', String(expiredState.docId));
|
|
}
|
|
|
|
const daysMax = expiredFilterDaysMax?.value ?? '';
|
|
|
|
if (daysMax !== '' && daysMax !== null) {
|
|
params.set('days_left_max', String(daysMax));
|
|
}
|
|
|
|
return params;
|
|
}
|
|
|
|
function renderExpiredDetail(rows, meta) {
|
|
const total = Number(meta?.total || 0);
|
|
const perPage = Number(meta?.per_page || expiredState.perPage);
|
|
const page = Number(meta?.page || expiredState.page);
|
|
const maxPage = total ? Math.ceil(total / perPage) : 1;
|
|
|
|
if (expiredDetailPageText) {
|
|
expiredDetailPageText.textContent = String(page);
|
|
}
|
|
|
|
if (expiredDetailInfo) {
|
|
const start = total ? ((page - 1) * perPage + 1) : 0;
|
|
const end = Math.min(page * perPage, total);
|
|
|
|
expiredDetailInfo.textContent = total
|
|
? `Menampilkan ${start}-${end} dari ${total} data`
|
|
: 'Tidak ada data';
|
|
}
|
|
|
|
if (expiredDetailPrevBtn) {
|
|
expiredDetailPrevBtn.disabled = page <= 1;
|
|
}
|
|
|
|
if (expiredDetailNextBtn) {
|
|
expiredDetailNextBtn.disabled = page >= maxPage;
|
|
}
|
|
|
|
if (!expiredDetailTbody) return;
|
|
|
|
if (!rows || !rows.length) {
|
|
expiredDetailTbody.innerHTML = `
|
|
<tr>
|
|
<td colspan="7" class="text-muted small">Tidak ada data</td>
|
|
</tr>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
expiredDetailTbody.innerHTML = rows.map((row, idx) => {
|
|
const no = (page - 1) * perPage + (idx + 1);
|
|
|
|
const unit = escapeHtml(row.unit_name || row.nama_unit || '-');
|
|
const noDok = escapeHtml(row.no_dokumen || row.nomor_dokumen || '-');
|
|
const nama = escapeHtml(row.nama_dokumen || row.nama_document || row.nama || '-');
|
|
const tgl = escapeHtml(row.tgl_expired_label || row.tgl_expired || row.expired_date || '-');
|
|
|
|
const daysLeft = row.days_left === null || row.days_left === undefined
|
|
? '-'
|
|
: escapeHtml(row.days_left);
|
|
|
|
const previewUrl = row.preview_url || row.url || '#';
|
|
|
|
return `
|
|
<tr>
|
|
<td>${no}</td>
|
|
<td>${unit}</td>
|
|
<td>${noDok}</td>
|
|
<td>${nama}</td>
|
|
<td>${tgl}</td>
|
|
<td>${daysLeft}</td>
|
|
<td>
|
|
<a class="btn btn-sm btn-outline-primary"
|
|
href="${previewUrl}"
|
|
target="_blank"
|
|
rel="noopener">
|
|
Preview
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
function loadExpiredDetail() {
|
|
setExpiredDetailLoading();
|
|
|
|
const params = buildExpiredDetailParams();
|
|
|
|
ajaxGet(`/data/expired-notifications/detail?${params.toString()}`)
|
|
.then(r => r.json())
|
|
.then(res => {
|
|
if (!res?.status) {
|
|
setExpiredDetailLoading(res?.message || 'Gagal memuat data');
|
|
return;
|
|
}
|
|
|
|
renderExpiredDetail(res.data || [], res.meta || {});
|
|
})
|
|
.catch(() => {
|
|
setExpiredDetailLoading('Gagal memuat data detail expired');
|
|
});
|
|
}
|
|
|
|
function openExpiredDetail(docId = null) {
|
|
expiredState.docId = docId ? Number(docId) : null;
|
|
expiredState.page = 1;
|
|
|
|
/**
|
|
* Kalau klik dari item expired tertentu,
|
|
* filter hari dikosongkan supaya data berdasarkan doc_id tetap muncul.
|
|
*/
|
|
if (expiredState.docId && expiredFilterDaysMax) {
|
|
expiredFilterDaysMax.value = '';
|
|
}
|
|
|
|
showExpiredModal();
|
|
loadExpiredDetail();
|
|
}
|
|
|
|
/**
|
|
* Tombol "Detail" di header expired.
|
|
*/
|
|
if (expiredOpenDetailBtn) {
|
|
expiredOpenDetailBtn.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
|
|
expiredState.docId = null;
|
|
expiredState.page = 1;
|
|
|
|
if (expiredFilterDaysMax) {
|
|
expiredFilterDaysMax.value = '30';
|
|
}
|
|
|
|
openExpiredDetail(null);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Klik salah satu item expired dari dropdown.
|
|
* Nanti langsung buka modal detail sesuai dokumen.
|
|
*/
|
|
if (expiredListEl) {
|
|
expiredListEl.addEventListener('click', function(e) {
|
|
const item = e.target.closest('a.js-expired-notif-item');
|
|
|
|
if (!item) return;
|
|
|
|
e.preventDefault();
|
|
|
|
const docId = item.dataset.docId || null;
|
|
|
|
openExpiredDetail(docId);
|
|
});
|
|
}
|
|
|
|
if (expiredApplyFilterBtn) {
|
|
expiredApplyFilterBtn.addEventListener('click', function() {
|
|
expiredState.docId = null;
|
|
expiredState.page = 1;
|
|
loadExpiredDetail();
|
|
});
|
|
}
|
|
|
|
if (expiredResetFilterBtn) {
|
|
expiredResetFilterBtn.addEventListener('click', function() {
|
|
expiredState.docId = null;
|
|
expiredState.page = 1;
|
|
|
|
if (expiredFilterDaysMax) {
|
|
expiredFilterDaysMax.value = '30';
|
|
}
|
|
|
|
loadExpiredDetail();
|
|
});
|
|
}
|
|
|
|
if (expiredDetailPrevBtn) {
|
|
expiredDetailPrevBtn.addEventListener('click', function() {
|
|
if (expiredState.page <= 1) return;
|
|
|
|
expiredState.page -= 1;
|
|
loadExpiredDetail();
|
|
});
|
|
}
|
|
|
|
if (expiredDetailNextBtn) {
|
|
expiredDetailNextBtn.addEventListener('click', function() {
|
|
expiredState.page += 1;
|
|
loadExpiredDetail();
|
|
});
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| LOAD PERTAMA
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
loadNotifications();
|
|
loadExpiredNotifications();
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| REFRESH OTOMATIS
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
setInterval(function() {
|
|
loadNotifications();
|
|
loadExpiredNotifications();
|
|
}, 60000);
|
|
});
|
|
</script>
|