@page "/rewards/manage" @using LibraryManagement.Shared.Models @using BlazorWebAssembly.Services @using Microsoft.AspNetCore.Authorization @attribute [Authorize(Roles = "Librarian")] @inject LibraryApiClient ApiClient @inject IJSRuntime JS

Rewards Management

Review and fulfill loyalty reward claims from library members.

@if (_isLoading) {
} else { @if (_activeTab == "pending") {
@if (!_pendingRedemptions.Any()) {

No pending redemptions at the moment.

} else {
@foreach (var r in _pendingRedemptions.OrderBy(x => x.RedeemedAt)) { }
Member Reward Points Claimed Date Status Action
@(string.IsNullOrEmpty(r.UserName) || r.UserName == "Unknown Member" ? "U" : r.UserName.Substring(0, 1).ToUpper())
@(r.UserName ?? "Unknown Member")

@r.RewardName

ID: @(r.Id.Length > 8 ? r.Id[..8] : r.Id)

@r.PointCost.ToString("N0") pts @r.RedeemedAt.ToString("MMM dd, yyyy") Pending
}
} else if (_activeTab == "history") {
@if (!_allMembersHistory.Any()) {

No loyalty history found.

} else {
@foreach (var member in FilteredMembers) {
@(member.UserName.Length >= 2 ? member.UserName.Substring(0, 2).ToUpper() : "?")

@member.UserName

@member.UserEmail

Current Balance

@member.CurrentBalance.ToString("N0") PTS

Tier

@member.Tier
@if (_expandedMemberId == member.AccountId) {

Points History

@foreach (var entry in member.History.OrderByDescending(x => x.CreatedAt)) {

@entry.Description

@entry.CreatedAt.ToString("MMM dd, yyyy HH:mm")

@(entry.PointDelta >= 0 ? "+" : "")@entry.PointDelta
}

Redemption History

@foreach (var red in member.Redemptions.OrderByDescending(x => x.RedeemedAt)) {

@red.RewardName

@red.RedeemedAt.ToString("MMM dd, yyyy")

@red.PointCost pts

@red.Status
}
}
}
}
} }
@code { private string _activeTab = "pending"; private bool _isLoading = true; private IEnumerable _pendingRedemptions = Enumerable.Empty(); private IEnumerable _allMembersHistory = Enumerable.Empty(); private string _searchQuery = ""; private string? _expandedMemberId; protected override async Task OnInitializedAsync() { await LoadDataAsync(); } private async Task LoadDataAsync() { _isLoading = true; try { _pendingRedemptions = await ApiClient.GetPendingRedemptionsAsync(); _allMembersHistory = await ApiClient.GetAllMembersPointsHistoryAsync(); } catch (Exception ex) { Console.WriteLine($"Error loading rewards manage data: {ex.Message}"); } finally { _isLoading = false; } } private IEnumerable FilteredMembers => string.IsNullOrWhiteSpace(_searchQuery) ? _allMembersHistory : _allMembersHistory.Where(m => m.UserName.Contains(_searchQuery, StringComparison.OrdinalIgnoreCase) || m.UserEmail.Contains(_searchQuery, StringComparison.OrdinalIgnoreCase)); private void ToggleMember(string accountId) { if (_expandedMemberId == accountId) _expandedMemberId = null; else _expandedMemberId = accountId; } private async Task FulfillAsync(LoyaltyRedemptionDto redemption) { bool confirmed = await JS.InvokeAsync("confirm", $"Fulfill {redemption.RewardName} for {redemption.UserName}?"); if (!confirmed) return; var result = await ApiClient.FulfillRedemptionAsync(redemption.Id); if (result.Success) { await LoadDataAsync(); await JS.InvokeVoidAsync("alert", result.Message); } else { await JS.InvokeVoidAsync("alert", result.Message); } } }