216 lines
12 KiB
JavaScript
216 lines
12 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
const selectAll = document.getElementById('select-all-invoices');
|
|
const invoiceChecks = document.querySelectorAll('.invoice-checkbox');
|
|
const bulkToolbar = document.getElementById('bulk-toolbar');
|
|
const selectedCount = document.getElementById('selected-count');
|
|
if (selectAll && invoiceChecks.length) {
|
|
function updateBulkToolbar() {
|
|
const checked = document.querySelectorAll('.invoice-checkbox:checked');
|
|
const count = checked.length;
|
|
if (count > 0) {
|
|
bulkToolbar.classList.remove('hidden');
|
|
bulkToolbar.classList.add('flex');
|
|
selectedCount.textContent = count + ' selected';
|
|
invoiceChecks.forEach(function (cb) { cb.closest('tr').classList.toggle('bg-blue-50/40', cb.checked); });
|
|
} else {
|
|
bulkToolbar.classList.add('hidden');
|
|
bulkToolbar.classList.remove('flex');
|
|
selectedCount.textContent = '0 selected';
|
|
invoiceChecks.forEach(function (cb) { cb.closest('tr').classList.remove('bg-blue-50/40'); });
|
|
}
|
|
}
|
|
selectAll.addEventListener('change', function () {
|
|
invoiceChecks.forEach(function (cb) { cb.checked = selectAll.checked; });
|
|
updateBulkToolbar();
|
|
});
|
|
invoiceChecks.forEach(function (cb) {
|
|
cb.addEventListener('change', function () {
|
|
var allChecked = true;
|
|
invoiceChecks.forEach(function (c) { if (!c.checked) allChecked = false; });
|
|
selectAll.checked = allChecked;
|
|
updateBulkToolbar();
|
|
});
|
|
});
|
|
}
|
|
var expandBtns = document.querySelectorAll('.expand-btn');
|
|
expandBtns.forEach(function (btn) {
|
|
btn.addEventListener('click', function () {
|
|
var row = this.closest('tr');
|
|
var detailRow = row.nextElementSibling;
|
|
var icon = this.querySelector('.expand-icon');
|
|
if (detailRow && detailRow.classList.contains('expand-detail')) {
|
|
detailRow.classList.toggle('hidden');
|
|
if (detailRow.classList.contains('hidden')) { icon.style.transform = 'rotate(0deg)'; }
|
|
else { icon.style.transform = 'rotate(90deg)'; }
|
|
}
|
|
});
|
|
});
|
|
(function () {
|
|
var searchInput = document.getElementById('product-search');
|
|
var catSelect = document.getElementById('product-category');
|
|
var tbody = document.getElementById('product-tbody');
|
|
var infoEl = document.getElementById('product-info');
|
|
if (!searchInput || !catSelect || !tbody || !infoEl) return;
|
|
var productRows = Array.prototype.slice.call(tbody.querySelectorAll('tr'));
|
|
function filterProducts() {
|
|
var q = searchInput.value.toLowerCase().trim();
|
|
var cat = catSelect.value;
|
|
var visible = 0;
|
|
var lowStock = 0;
|
|
productRows.forEach(function (tr) {
|
|
var cells = tr.querySelectorAll('td');
|
|
if (cells.length < 5) return;
|
|
var sku = cells[0].textContent.toLowerCase();
|
|
var name = cells[1].textContent.toLowerCase();
|
|
var category = cells[2].textContent.trim();
|
|
var stockText = cells[3].textContent.trim();
|
|
var stockNum = parseInt(stockText.replace(/[^0-9-]/g, '')) || 0;
|
|
var matchSearch = q === '' || sku.indexOf(q) !== -1 || name.indexOf(q) !== -1;
|
|
var matchCat = cat === '' || category === cat;
|
|
if (matchSearch && matchCat) {
|
|
tr.style.display = '';
|
|
visible++;
|
|
if (stockNum > 0 && stockNum < 100) lowStock++;
|
|
} else {
|
|
tr.style.display = 'none';
|
|
}
|
|
});
|
|
infoEl.innerHTML = 'Showing <b class="text-gray-600">' + visible + '</b> of <b class="text-gray-600">' + productRows.length + '</b> products';
|
|
var lowEl = infoEl.parentElement.querySelector('.text-amber-600');
|
|
if (lowEl) lowEl.textContent = lowStock;
|
|
}
|
|
searchInput.addEventListener('input', filterProducts);
|
|
catSelect.addEventListener('change', filterProducts);
|
|
})();
|
|
(function () {
|
|
var tbody = document.getElementById('transactions-tbody');
|
|
var infoEl = document.getElementById('transactions-info');
|
|
var pageBtnsEl = document.getElementById('transactions-page-btns');
|
|
if (!tbody || !infoEl || !pageBtnsEl) return;
|
|
var perPage = 10;
|
|
var totalEntries = 120;
|
|
var totalPages = Math.ceil(totalEntries / perPage);
|
|
var currentPage = 1;
|
|
var accounts = [
|
|
'PT. MegaCorp - 001-234-5678', 'TechDistrib Inc. - 002-987-6543',
|
|
'CloudHost Ltd. - 003-456-7890', 'OfficePro Supply - 004-567-8901',
|
|
'MegaNetwork Corp - 005-678-9012', 'Consulting Plus - 006-789-0123',
|
|
'DataSys Solutions - 007-890-1234', 'GreenEnergy Corp - 008-901-2345',
|
|
'SmartBuild Ltd. - 009-012-3456', 'MediCare Supplies - 010-123-4567',
|
|
'AquaPure Systems - 011-234-5678', 'FinServe Global - 012-345-6789',
|
|
'LogiTrack Inc. - 013-456-7890', 'BioHealth Labs - 014-567-8901',
|
|
'EduPrime Academy - 015-678-9012'
|
|
];
|
|
var methods = ['Wire Transfer', 'Bank Transfer', 'Credit Card', 'ACH Transfer', 'Digital Wallet'];
|
|
var statuses = [
|
|
{ label: 'Success', chip: 'chip-green' },
|
|
{ label: 'Pending', chip: 'chip-amber' },
|
|
{ label: 'Processed', chip: 'chip-blue' },
|
|
{ label: 'Failed', chip: 'chip-red' }
|
|
];
|
|
function rand(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
|
|
function pick(arr) { return arr[rand(0, arr.length - 1)]; }
|
|
var allData = [];
|
|
for (var i = 1; i <= totalEntries; i++) {
|
|
var amount = rand(500, 50000) + rand(0, 99) / 100;
|
|
allData.push({
|
|
id: 'TRX-2026-' + String(i).padStart(3, '0'),
|
|
from: pick(accounts),
|
|
to: pick(accounts),
|
|
nominal: '$' + amount.toFixed(2),
|
|
status: pick(statuses),
|
|
method: pick(methods)
|
|
});
|
|
}
|
|
var originalData = [
|
|
{ id: 'TRX-2026-001', from: 'PT. MegaCorp - 001-234-5678', to: 'TechDistrib Inc. - 002-987-6543', nominal: '$24,500.00', status: { label: 'Success', chip: 'chip-green' }, method: 'Wire Transfer' },
|
|
{ id: 'TRX-2026-002', from: 'CloudHost Ltd. - 003-456-7890', to: 'PT. MegaCorp - 001-234-5678', nominal: '$12,800.00', status: { label: 'Pending', chip: 'chip-amber' }, method: 'Bank Transfer' },
|
|
{ id: 'TRX-2026-003', from: 'OfficePro Supply - 004-567-8901', to: 'PT. MegaCorp - 001-234-5678', nominal: '$6,200.00', status: { label: 'Processed', chip: 'chip-blue' }, method: 'Credit Card' },
|
|
{ id: 'TRX-2026-004', from: 'PT. MegaCorp - 001-234-5678', to: 'MegaNetwork Corp - 005-678-9012', nominal: '$32,000.00', status: { label: 'Failed', chip: 'chip-red' }, method: 'Wire Transfer' },
|
|
{ id: 'TRX-2026-005', from: 'Consulting Plus - 006-789-0123', to: 'PT. MegaCorp - 001-234-5678', nominal: '$18,000.00', status: { label: 'Success', chip: 'chip-green' }, method: 'Bank Transfer' },
|
|
{ id: 'TRX-2026-006', from: 'DataSys Solutions - 007-890-1234', to: 'PT. MegaCorp - 001-234-5678', nominal: '$45,200.00', status: { label: 'Pending', chip: 'chip-amber' }, method: 'ACH Transfer' },
|
|
{ id: 'TRX-2026-007', from: 'PT. MegaCorp - 001-234-5678', to: 'GreenEnergy Corp - 008-901-2345', nominal: '$28,900.00', status: { label: 'Processed', chip: 'chip-blue' }, method: 'Wire Transfer' },
|
|
{ id: 'TRX-2026-008', from: 'SmartBuild Ltd. - 009-012-3456', to: 'PT. MegaCorp - 001-234-5678', nominal: '$8,750.00', status: { label: 'Failed', chip: 'chip-red' }, method: 'Credit Card' },
|
|
{ id: 'TRX-2026-009', from: 'PT. MegaCorp - 001-234-5678', to: 'MediCare Supplies - 010-123-4567', nominal: '$19,300.00', status: { label: 'Success', chip: 'chip-green' }, method: 'Bank Transfer' },
|
|
{ id: 'TRX-2026-010', from: 'AquaPure Systems - 011-234-5678', to: 'PT. MegaCorp - 001-234-5678', nominal: '$11,400.00', status: { label: 'Pending', chip: 'chip-amber' }, method: 'ACH Transfer' }
|
|
];
|
|
for (var idx = 0; idx < originalData.length; idx++) {
|
|
allData[idx] = originalData[idx];
|
|
}
|
|
function renderPage(page) {
|
|
var start = (page - 1) * perPage;
|
|
var end = Math.min(start + perPage, totalEntries);
|
|
var html = '';
|
|
for (var i = start; i < end; i++) {
|
|
var d = allData[i];
|
|
html += '<tr class="bg-white hover:bg-gray-50/50 transition">' +
|
|
'<td class="px-4 py-3 text-sm text-gray-700 font-mono font-medium">' + d.id + '</td>' +
|
|
'<td class="px-4 py-3 text-sm text-gray-600">' + d.from + '</td>' +
|
|
'<td class="px-4 py-3 text-sm text-gray-600">' + d.to + '</td>' +
|
|
'<td class="px-4 py-3 text-sm text-gray-700 text-right font-mono">' + d.nominal + '</td>' +
|
|
'<td class="px-4 py-3 text-center"><span class="chip ' + d.status.chip + '">' + d.status.label + '</span></td>' +
|
|
'<td class="px-4 py-3 text-sm text-gray-600">' + d.method + '</td></tr>';
|
|
}
|
|
tbody.innerHTML = html;
|
|
infoEl.innerHTML = 'Showing <b class="text-gray-600">' + (start + 1) + '</b> to <b class="text-gray-600">' + end + '</b> of <b class="text-gray-600">' + totalEntries + '</b> entries';
|
|
var btnsHtml = '';
|
|
var prevDisabled = page === 1;
|
|
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-500 hover:bg-gray-50 transition' + (prevDisabled ? ' cursor-not-allowed opacity-50' : '') + '" data-page="prev"' + (prevDisabled ? ' disabled' : '') + '>Previous</button>';
|
|
var maxVisible = 7;
|
|
var startPage, endPage;
|
|
if (totalPages <= maxVisible) {
|
|
startPage = 1;
|
|
endPage = totalPages;
|
|
} else {
|
|
var half = Math.floor(maxVisible / 2);
|
|
if (page <= half + 1) {
|
|
startPage = 1;
|
|
endPage = maxVisible;
|
|
} else if (page >= totalPages - half) {
|
|
startPage = totalPages - maxVisible + 1;
|
|
endPage = totalPages;
|
|
} else {
|
|
startPage = page - half;
|
|
endPage = page + half;
|
|
}
|
|
}
|
|
if (startPage > 1) {
|
|
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition" data-page="1">1</button>';
|
|
if (startPage > 2) {
|
|
btnsHtml += '<span class="px-1 text-gray-400">...</span>';
|
|
}
|
|
}
|
|
for (var p = startPage; p <= endPage; p++) {
|
|
var isActive = p === page;
|
|
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border' +
|
|
(isActive ? ' bg-blue-600 text-white border-blue-600' : ' border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition') +
|
|
'" data-page="' + p + '">' + p + '</button>';
|
|
}
|
|
if (endPage < totalPages) {
|
|
if (endPage < totalPages - 1) {
|
|
btnsHtml += '<span class="px-1 text-gray-400">...</span>';
|
|
}
|
|
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-700 hover:bg-gray-50 transition" data-page="' + totalPages + '">' + totalPages + '</button>';
|
|
}
|
|
var nextDisabled = page === totalPages;
|
|
btnsHtml += '<button class="px-3 py-1.5 text-xs font-medium rounded-lg border border-gray-200 bg-white text-gray-500 hover:bg-gray-50 transition' + (nextDisabled ? ' cursor-not-allowed opacity-50' : '') + '" data-page="next"' + (nextDisabled ? ' disabled' : '') + '>Next</button>';
|
|
pageBtnsEl.innerHTML = btnsHtml;
|
|
var btns = pageBtnsEl.querySelectorAll('button:not([disabled])');
|
|
btns.forEach(function (btn) {
|
|
btn.addEventListener('click', function () {
|
|
var target = this.getAttribute('data-page');
|
|
var newPage = page;
|
|
if (target === 'prev') newPage = page - 1;
|
|
else if (target === 'next') newPage = page + 1;
|
|
else newPage = parseInt(target);
|
|
if (newPage >= 1 && newPage <= totalPages) {
|
|
currentPage = newPage;
|
|
renderPage(currentPage);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
renderPage(1);
|
|
})();
|
|
});
|