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 shadow-sm mb-3">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<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>
|
<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>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<div class="table-responsive" style="max-height: 500px; overflow-y: auto;">
|
<div class="table-responsive" style="max-height: 500px; overflow-y: auto;">
|
||||||
@@ -62,11 +70,12 @@
|
|||||||
<th style="width: 80px;">Status</th>
|
<th style="width: 80px;">Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody id="transactionTableBody">
|
||||||
@for (int i = 0; i < Model.PreviewTransactions.Count; i++)
|
@for (int i = 0; i < Model.PreviewTransactions.Count; i++)
|
||||||
{
|
{
|
||||||
var preview = Model.PreviewTransactions[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>
|
<td>
|
||||||
<input type="checkbox" data-index="@i"
|
<input type="checkbox" data-index="@i"
|
||||||
class="form-check-input transaction-checkbox"
|
class="form-check-input transaction-checkbox"
|
||||||
@@ -227,6 +236,10 @@ else
|
|||||||
@section Scripts {
|
@section Scripts {
|
||||||
<partial name="_ValidationScriptsPartial" />
|
<partial name="_ValidationScriptsPartial" />
|
||||||
<script>
|
<script>
|
||||||
|
let currentPage = 0;
|
||||||
|
const pageSize = 100;
|
||||||
|
const totalRows = @Model.PreviewTransactions.Count;
|
||||||
|
|
||||||
function togglePaymentSelection() {
|
function togglePaymentSelection() {
|
||||||
const mode = document.querySelector('input[name="PaymentMode"]:checked').value;
|
const mode = document.querySelector('input[name="PaymentMode"]:checked').value;
|
||||||
const cardRow = document.getElementById('cardSelectRow');
|
const cardRow = document.getElementById('cardSelectRow');
|
||||||
@@ -246,8 +259,10 @@ else
|
|||||||
function updateSelectedCount() {
|
function updateSelectedCount() {
|
||||||
const checkboxes = document.querySelectorAll('.transaction-checkbox:checked');
|
const checkboxes = document.querySelectorAll('.transaction-checkbox:checked');
|
||||||
const count = checkboxes.length;
|
const count = checkboxes.length;
|
||||||
document.getElementById('selectedCount').textContent = count;
|
const selectedCountEl = document.getElementById('selectedCount');
|
||||||
document.getElementById('selectedCountButton').textContent = count;
|
const selectedCountButtonEl = document.getElementById('selectedCountButton');
|
||||||
|
if (selectedCountEl) selectedCountEl.textContent = count;
|
||||||
|
if (selectedCountButtonEl) selectedCountButtonEl.textContent = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAllTransactionAccounts() {
|
function updateAllTransactionAccounts() {
|
||||||
@@ -255,6 +270,39 @@ else
|
|||||||
// No action needed - we'll read the global account on form submit
|
// 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() {
|
function prepareFormData() {
|
||||||
// Collect selected indices
|
// Collect selected indices
|
||||||
const selectedIndices = [];
|
const selectedIndices = [];
|
||||||
@@ -264,7 +312,7 @@ else
|
|||||||
document.getElementById('selectedIndices').value = selectedIndices.join(',');
|
document.getElementById('selectedIndices').value = selectedIndices.join(',');
|
||||||
|
|
||||||
// Get the global account ID
|
// Get the global account ID
|
||||||
const globalAccountId = document.getElementById('globalAccountId').value;
|
const globalAccountId = document.getElementById('globalAccountId')?.value;
|
||||||
if (!globalAccountId) {
|
if (!globalAccountId) {
|
||||||
alert('Please select an account for all transactions');
|
alert('Please select an account for all transactions');
|
||||||
return false;
|
return false;
|
||||||
@@ -292,6 +340,11 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize on page load
|
// Initialize on page load
|
||||||
document.addEventListener('DOMContentLoaded', togglePaymentSelection);
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
togglePaymentSelection();
|
||||||
|
if (totalRows > pageSize) {
|
||||||
|
showPage(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user