292 lines
11 KiB
JavaScript
292 lines
11 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
const pageEl = document.getElementById('history-page');
|
|
if (!pageEl) return;
|
|
|
|
const apiUrl = pageEl.dataset.historyApi;
|
|
const detailBase = pageEl.dataset.historyDetailBase || '/upst/history/details/__id__';
|
|
|
|
const loadingEl = document.getElementById('history-loading');
|
|
const emptyEl = document.getElementById('history-empty');
|
|
const listEl = document.getElementById('history-list');
|
|
const paginationEl = document.getElementById('history-pagination');
|
|
const pageInfoEl = document.getElementById('history-page-info');
|
|
const totalInfoEl = document.getElementById('history-total-info');
|
|
const pageButtonsEl = document.getElementById('history-page-buttons');
|
|
const prevBtn = document.getElementById('history-prev-page');
|
|
const nextBtn = document.getElementById('history-next-page');
|
|
const fromDateInput = document.getElementById('history-from-date-filter');
|
|
const toDateInput = document.getElementById('history-to-date-filter');
|
|
const applyFilterBtn = document.getElementById('history-apply-filter');
|
|
const resetFilterBtn = document.getElementById('history-reset-filter');
|
|
|
|
const state = {
|
|
page: 1,
|
|
pageSize: 5,
|
|
totalPages: 1,
|
|
totalItems: 0,
|
|
fromDate: '',
|
|
toDate: ''
|
|
};
|
|
|
|
function formatTanggal(dateString) {
|
|
const date = new Date(dateString);
|
|
return new Intl.DateTimeFormat('id-ID', {
|
|
day: '2-digit',
|
|
month: 'short',
|
|
year: 'numeric'
|
|
}).format(date);
|
|
}
|
|
|
|
function formatWaktu(dateString) {
|
|
const date = new Date(dateString);
|
|
return new Intl.DateTimeFormat('id-ID', {
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
}).format(date);
|
|
}
|
|
|
|
function getStatusMarkup(status) {
|
|
if ((status || '').toLowerCase() === 'completed') {
|
|
return '<span class="bg-green-50 text-green-600 px-3 py-1 rounded-lg text-[10px] font-black uppercase border border-green-100">Selesai</span>';
|
|
}
|
|
|
|
return '<span class="bg-blue-50 text-blue-600 px-3 py-1 rounded-lg text-[10px] font-black uppercase border border-blue-100 animate-pulse">Proses</span>';
|
|
}
|
|
|
|
function buildDetailUrl(id) {
|
|
return detailBase.replace('__id__', String(id));
|
|
}
|
|
|
|
function renderItems(items) {
|
|
listEl.innerHTML = '';
|
|
|
|
items.forEach(function (item) {
|
|
const card = document.createElement('a');
|
|
card.href = buildDetailUrl(item.id);
|
|
card.className = 'block group';
|
|
card.innerHTML = `
|
|
<div class="bg-white rounded-3xl p-5 shadow-sm border border-gray-100 group-hover:shadow-md group-hover:-translate-y-1 transition-all duration-300">
|
|
<div class="flex justify-between items-start mb-4">
|
|
<div class="space-y-0.5">
|
|
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-widest">Nomor Dokumen</p>
|
|
<p class="text-sm font-black text-gray-800">${item.noSpj}</p>
|
|
</div>
|
|
${getStatusMarkup(item.status)}
|
|
</div>
|
|
|
|
<div class="flex items-center gap-4 bg-gray-50/80 p-3 rounded-2xl border border-dashed border-gray-200">
|
|
<div class="w-12 h-12 bg-upst rounded-xl flex items-center justify-center shadow-inner">
|
|
<i class="w-6 h-6 text-white" data-lucide="truck"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<div class="flex justify-between items-baseline gap-2">
|
|
<h2 class="font-black text-gray-900 leading-tight">${item.plat}</h2>
|
|
<span class="text-[11px] font-bold text-upst whitespace-nowrap">${formatWaktu(item.tanggalWaktu)}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center gap-2">
|
|
<span class="text-xs text-gray-500 font-medium">${item.kode}</span>
|
|
<span class="text-[10px] text-gray-400 font-semibold whitespace-nowrap">${formatTanggal(item.tanggalWaktu)}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 flex items-center justify-between gap-3">
|
|
<div class="flex items-center gap-2 min-w-0">
|
|
<div class="w-2 h-2 rounded-full bg-upst/40"></div>
|
|
<div class="flex flex-col min-w-0">
|
|
<span class="text-[10px] text-gray-400 font-bold uppercase">Tujuan Akhir</span>
|
|
<span class="text-sm font-bold text-gray-700 truncate">${item.tujuan}</span>
|
|
</div>
|
|
</div>
|
|
<div class="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center group-hover:bg-upst transition-colors shrink-0">
|
|
<i class="w-4 h-4" data-lucide="chevron-right"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
listEl.appendChild(card);
|
|
});
|
|
|
|
if (window.lucide) {
|
|
window.lucide.createIcons();
|
|
}
|
|
}
|
|
|
|
function renderPagination() {
|
|
const hasItems = state.totalItems > 0;
|
|
paginationEl.classList.toggle('hidden', !hasItems);
|
|
if (!hasItems) return;
|
|
|
|
pageInfoEl.textContent = `Halaman ${state.page} dari ${state.totalPages}`;
|
|
totalInfoEl.textContent = `${state.totalItems} data`;
|
|
prevBtn.disabled = state.page <= 1;
|
|
nextBtn.disabled = state.page >= state.totalPages;
|
|
|
|
pageButtonsEl.innerHTML = '';
|
|
const pages = [];
|
|
const startPage = Math.max(1, state.page - 2);
|
|
const endPage = Math.min(state.totalPages, state.page + 2);
|
|
|
|
if (startPage > 1) {
|
|
pages.push(1);
|
|
if (startPage > 2) pages.push('ellipsis-left');
|
|
}
|
|
|
|
for (let page = startPage; page <= endPage; page++) {
|
|
pages.push(page);
|
|
}
|
|
|
|
if (endPage < state.totalPages) {
|
|
if (endPage < state.totalPages - 1) pages.push('ellipsis-right');
|
|
pages.push(state.totalPages);
|
|
}
|
|
|
|
pages.forEach(function (page) {
|
|
if (typeof page !== 'number') {
|
|
const ellipsis = document.createElement('span');
|
|
ellipsis.className = 'w-10 h-10 flex items-center justify-center text-xs font-black text-gray-400';
|
|
ellipsis.textContent = '...';
|
|
pageButtonsEl.appendChild(ellipsis);
|
|
return;
|
|
}
|
|
|
|
const btn = document.createElement('button');
|
|
btn.type = 'button';
|
|
btn.textContent = String(page);
|
|
btn.className = page === state.page
|
|
? 'w-10 h-10 rounded-2xl bg-upst text-white text-xs font-black'
|
|
: 'w-10 h-10 rounded-2xl border border-gray-200 text-gray-700 text-xs font-black bg-white';
|
|
btn.addEventListener('click', function () {
|
|
if (page === state.page) return;
|
|
loadHistory(page);
|
|
});
|
|
pageButtonsEl.appendChild(btn);
|
|
});
|
|
}
|
|
|
|
function setLoading(isLoading) {
|
|
loadingEl.classList.toggle('hidden', !isLoading);
|
|
if (isLoading) {
|
|
emptyEl.classList.add('hidden');
|
|
listEl.innerHTML = '';
|
|
paginationEl.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
function showEmpty() {
|
|
listEl.innerHTML = '';
|
|
emptyEl.classList.remove('hidden');
|
|
paginationEl.classList.add('hidden');
|
|
if (window.lucide) {
|
|
window.lucide.createIcons();
|
|
}
|
|
}
|
|
|
|
async function loadHistory(page) {
|
|
state.page = page || 1;
|
|
setLoading(true);
|
|
|
|
try {
|
|
const params = new URLSearchParams({
|
|
page: String(state.page),
|
|
pageSize: String(state.pageSize)
|
|
});
|
|
|
|
if (state.fromDate) {
|
|
params.set('fromDate', state.fromDate);
|
|
}
|
|
|
|
if (state.toDate) {
|
|
params.set('toDate', state.toDate);
|
|
}
|
|
|
|
const response = await fetch(`${apiUrl}?${params.toString()}`, { cache: 'no-store' });
|
|
if (!response.ok) {
|
|
throw new Error('Gagal memuat history');
|
|
}
|
|
|
|
const data = await response.json();
|
|
state.page = data.page || 1;
|
|
state.totalPages = data.totalPages || 1;
|
|
state.totalItems = data.totalItems || 0;
|
|
|
|
loadingEl.classList.add('hidden');
|
|
if (!data.items || data.items.length === 0) {
|
|
showEmpty();
|
|
return;
|
|
}
|
|
|
|
emptyEl.classList.add('hidden');
|
|
renderItems(data.items);
|
|
renderPagination();
|
|
} catch (error) {
|
|
console.error(error);
|
|
loadingEl.classList.add('hidden');
|
|
emptyEl.classList.remove('hidden');
|
|
emptyEl.innerHTML = `
|
|
<div class="w-16 h-16 bg-red-50 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<i class="w-8 h-8 text-red-400" data-lucide="triangle-alert"></i>
|
|
</div>
|
|
<h3 class="text-base font-black text-gray-900 mb-1">Gagal Memuat Riwayat</h3>
|
|
<p class="text-sm text-gray-500">Silakan coba lagi beberapa saat.</p>
|
|
`;
|
|
if (window.lucide) {
|
|
window.lucide.createIcons();
|
|
}
|
|
}
|
|
}
|
|
|
|
function applyDateRangeFilter() {
|
|
const nextFromDate = fromDateInput?.value || '';
|
|
const nextToDate = toDateInput?.value || '';
|
|
|
|
if (nextFromDate && nextToDate && nextFromDate > nextToDate) {
|
|
const temp = nextFromDate;
|
|
state.fromDate = nextToDate;
|
|
state.toDate = temp;
|
|
if (fromDateInput) fromDateInput.value = state.fromDate;
|
|
if (toDateInput) toDateInput.value = state.toDate;
|
|
} else {
|
|
state.fromDate = nextFromDate;
|
|
state.toDate = nextToDate;
|
|
}
|
|
|
|
loadHistory(1);
|
|
}
|
|
|
|
applyFilterBtn?.addEventListener('click', function () {
|
|
applyDateRangeFilter();
|
|
});
|
|
|
|
resetFilterBtn?.addEventListener('click', function () {
|
|
state.fromDate = '';
|
|
state.toDate = '';
|
|
if (fromDateInput) fromDateInput.value = '';
|
|
if (toDateInput) toDateInput.value = '';
|
|
loadHistory(1);
|
|
});
|
|
|
|
[fromDateInput, toDateInput].forEach(function (input) {
|
|
input?.addEventListener('keydown', function (event) {
|
|
if (event.key === 'Enter') {
|
|
event.preventDefault();
|
|
applyDateRangeFilter();
|
|
}
|
|
});
|
|
});
|
|
|
|
prevBtn?.addEventListener('click', function () {
|
|
if (state.page > 1) {
|
|
loadHistory(state.page - 1);
|
|
}
|
|
});
|
|
|
|
nextBtn?.addEventListener('click', function () {
|
|
if (state.page < state.totalPages) {
|
|
loadHistory(state.page + 1);
|
|
}
|
|
});
|
|
|
|
loadHistory(1);
|
|
});
|