Add pagination to transaction preview for large imports
When uploading files with more than 100 transactions, the preview now displays transactions in pages of 100 rows at a time. This prevents browser freezing when rendering thousands of form inputs and dramatically improves page load performance. - Show first 100 transactions by default with pagination controls - All transactions remain in DOM but hidden for instant page switching - Update counters and form submission to work across all pages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,14 @@
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<strong>Transaction Preview (<span id="selectedCount">@Model.PreviewTransactions.Count(p => !p.IsDuplicate)</span> selected, @Model.PreviewTransactions.Count(p => p.IsDuplicate) duplicates)</strong>
|
||||
@if (Model.PreviewTransactions.Count > 100)
|
||||
{
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<small class="text-muted">Showing <span id="pageStart">1</span>-<span id="pageEnd">100</span> of @Model.PreviewTransactions.Count</small>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="previousPage()">Previous</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="nextPage()">Next</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive" style="max-height: 500px; overflow-y: auto;">
|
||||
@@ -62,11 +70,12 @@
|
||||
<th style="width: 80px;">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody id="transactionTableBody">
|
||||
@for (int i = 0; i < Model.PreviewTransactions.Count; i++)
|
||||
{
|
||||
var preview = Model.PreviewTransactions[i];
|
||||
<tr class="@(preview.IsDuplicate ? "table-secondary text-muted" : "")" data-index="@i">
|
||||
var displayStyle = i >= 100 ? "display: none;" : "";
|
||||
<tr class="@(preview.IsDuplicate ? "table-secondary text-muted" : "") transaction-row" data-index="@i" style="@displayStyle">
|
||||
<td>
|
||||
<input type="checkbox" data-index="@i"
|
||||
class="form-check-input transaction-checkbox"
|
||||
@@ -227,6 +236,10 @@ else
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
<script>
|
||||
let currentPage = 0;
|
||||
const pageSize = 100;
|
||||
const totalRows = @Model.PreviewTransactions.Count;
|
||||
|
||||
function togglePaymentSelection() {
|
||||
const mode = document.querySelector('input[name="PaymentMode"]:checked').value;
|
||||
const cardRow = document.getElementById('cardSelectRow');
|
||||
@@ -246,8 +259,10 @@ else
|
||||
function updateSelectedCount() {
|
||||
const checkboxes = document.querySelectorAll('.transaction-checkbox:checked');
|
||||
const count = checkboxes.length;
|
||||
document.getElementById('selectedCount').textContent = count;
|
||||
document.getElementById('selectedCountButton').textContent = count;
|
||||
const selectedCountEl = document.getElementById('selectedCount');
|
||||
const selectedCountButtonEl = document.getElementById('selectedCountButton');
|
||||
if (selectedCountEl) selectedCountEl.textContent = count;
|
||||
if (selectedCountButtonEl) selectedCountButtonEl.textContent = count;
|
||||
}
|
||||
|
||||
function updateAllTransactionAccounts() {
|
||||
@@ -255,6 +270,39 @@ else
|
||||
// No action needed - we'll read the global account on form submit
|
||||
}
|
||||
|
||||
function showPage(pageNum) {
|
||||
const rows = document.querySelectorAll('.transaction-row');
|
||||
const start = pageNum * pageSize;
|
||||
const end = start + pageSize;
|
||||
|
||||
rows.forEach((row, index) => {
|
||||
row.style.display = (index >= start && index < end) ? '' : 'none';
|
||||
});
|
||||
|
||||
// Update pagination display
|
||||
const pageStartEl = document.getElementById('pageStart');
|
||||
const pageEndEl = document.getElementById('pageEnd');
|
||||
if (pageStartEl && pageEndEl) {
|
||||
pageStartEl.textContent = start + 1;
|
||||
pageEndEl.textContent = Math.min(end, totalRows);
|
||||
}
|
||||
|
||||
currentPage = pageNum;
|
||||
}
|
||||
|
||||
function nextPage() {
|
||||
const maxPage = Math.ceil(totalRows / pageSize) - 1;
|
||||
if (currentPage < maxPage) {
|
||||
showPage(currentPage + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function previousPage() {
|
||||
if (currentPage > 0) {
|
||||
showPage(currentPage - 1);
|
||||
}
|
||||
}
|
||||
|
||||
function prepareFormData() {
|
||||
// Collect selected indices
|
||||
const selectedIndices = [];
|
||||
@@ -264,7 +312,7 @@ else
|
||||
document.getElementById('selectedIndices').value = selectedIndices.join(',');
|
||||
|
||||
// Get the global account ID
|
||||
const globalAccountId = document.getElementById('globalAccountId').value;
|
||||
const globalAccountId = document.getElementById('globalAccountId')?.value;
|
||||
if (!globalAccountId) {
|
||||
alert('Please select an account for all transactions');
|
||||
return false;
|
||||
@@ -292,6 +340,11 @@ else
|
||||
}
|
||||
|
||||
// Initialize on page load
|
||||
document.addEventListener('DOMContentLoaded', togglePaymentSelection);
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
togglePaymentSelection();
|
||||
if (totalRows > pageSize) {
|
||||
showPage(0);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user