feat(loyalty): add paginated transaction history to card detail
Some checks failed
Some checks failed
The store card detail page now shows paginated transaction history instead of a flat list of 50. Uses PlatformSettings.getRowsPerPage() for the page size (default 20), with Previous/Next navigation and "Page X of Y" indicator using server-rendered i18n. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -761,7 +761,8 @@
|
||||
"col_location": "Location",
|
||||
"col_notes": "Notes",
|
||||
"no_transactions": "No transactions yet",
|
||||
"card_label": "Card"
|
||||
"card_label": "Card",
|
||||
"page_x_of_y": "Page {page} of {pages}"
|
||||
},
|
||||
"enroll": {
|
||||
"title": "Enroll Customer",
|
||||
|
||||
@@ -11,6 +11,7 @@ function storeLoyaltyCardDetail() {
|
||||
cardId: null,
|
||||
card: null,
|
||||
transactions: [],
|
||||
txPagination: { page: 1, perPage: 20, total: 0, pages: 0 },
|
||||
|
||||
loading: false,
|
||||
error: null,
|
||||
@@ -38,6 +39,13 @@ function storeLoyaltyCardDetail() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use platform pagination setting if available
|
||||
if (window.PlatformSettings) {
|
||||
try {
|
||||
this.txPagination.perPage = await window.PlatformSettings.getRowsPerPage();
|
||||
} catch (e) { /* use default */ }
|
||||
}
|
||||
|
||||
await this.loadData();
|
||||
loyaltyCardDetailLog.info('=== LOYALTY CARD DETAIL PAGE INITIALIZATION COMPLETE ===');
|
||||
},
|
||||
@@ -67,18 +75,32 @@ function storeLoyaltyCardDetail() {
|
||||
}
|
||||
},
|
||||
|
||||
async loadTransactions() {
|
||||
async loadTransactions(page = 1) {
|
||||
try {
|
||||
const response = await apiClient.get(`/store/loyalty/cards/${this.cardId}/transactions?limit=50`);
|
||||
const skip = (page - 1) * this.txPagination.perPage;
|
||||
const response = await apiClient.get(
|
||||
`/store/loyalty/cards/${this.cardId}/transactions?skip=${skip}&limit=${this.txPagination.perPage}`
|
||||
);
|
||||
if (response && response.transactions) {
|
||||
this.transactions = response.transactions;
|
||||
loyaltyCardDetailLog.info(`Loaded ${this.transactions.length} transactions`);
|
||||
this.txPagination.total = response.total || 0;
|
||||
this.txPagination.page = page;
|
||||
this.txPagination.pages = Math.ceil(this.txPagination.total / this.txPagination.perPage);
|
||||
loyaltyCardDetailLog.info(`Loaded ${this.transactions.length} of ${this.txPagination.total} transactions (page ${page})`);
|
||||
}
|
||||
} catch (error) {
|
||||
loyaltyCardDetailLog.warn('Failed to load transactions:', error.message);
|
||||
}
|
||||
},
|
||||
|
||||
txPreviousPage() {
|
||||
if (this.txPagination.page > 1) this.loadTransactions(this.txPagination.page - 1);
|
||||
},
|
||||
|
||||
txNextPage() {
|
||||
if (this.txPagination.page < this.txPagination.pages) this.loadTransactions(this.txPagination.page + 1);
|
||||
},
|
||||
|
||||
formatNumber(num) {
|
||||
return num == null ? '0' : new Intl.NumberFormat('en-US').format(num);
|
||||
},
|
||||
|
||||
@@ -151,6 +151,23 @@
|
||||
</template>
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
|
||||
<!-- Pagination -->
|
||||
<div x-show="txPagination.pages > 1" class="px-4 py-3 border-t border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
||||
<button @click="txPreviousPage()" :disabled="txPagination.page <= 1"
|
||||
type="button"
|
||||
class="px-3 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50">
|
||||
{{ _('loyalty.common.previous') }}
|
||||
</button>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400"
|
||||
x-text="'{{ _('loyalty.store.card_detail.page_x_of_y') }}'.replace('{page}', txPagination.page).replace('{pages}', txPagination.pages)">
|
||||
</span>
|
||||
<button @click="txNextPage()" :disabled="txPagination.page >= txPagination.pages"
|
||||
type="button"
|
||||
class="px-3 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50">
|
||||
{{ _('loyalty.common.next') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user