@page "/user-insights" @using LibraryManagement.Shared.Models @using BlazorWebAssembly.Services @inject LibraryApiClient ApiClient @inject NavigationManager Navigation @using Microsoft.AspNetCore.Authorization @attribute [Authorize(Roles = "Librarian")]

User Insights

Analytics and data-driven visibility into library membership and reading patterns.

Total Members @(_totalMembers)
Active Subs @(_activeSubscriptions)
@if (_isLoading) {
@for (int i = 0; i < 3; i++) {
}
} else {

Top Readers

@if (!_activeReaders.Any()) {

No data available yet.

} @foreach (var (user, index) in _activeReaders.Take(5).Select((u, i) => (u, i))) { var maxRaw = _activeReaders.Max(u => u.RawValue); var pct = maxRaw > 0 ? (user.RawValue / maxRaw) * 100 : 0;
@(index + 1)

@user.Name

@user.ValueLabel

}

Point Leaders

@if (!_loyalty.Any()) {

No data available yet.

} @foreach (var (user, index) in _loyalty.Take(5).Select((u, i) => (u, i))) {
@(user.Name.Length >= 2 ? user.Name.Substring(0, 2).ToUpper() : "?")

@user.Name

@user.ValueLabel

#@(index + 1)
}

Top Subscribers

@if (!_subscribers.Any()) {

No data available yet.

} @foreach (var (user, index) in _subscribers.Take(5).Select((u, i) => (u, i))) {
@(index + 1)

@user.Name

@user.ValueLabel

}

Full Member Insights (All Users)

@foreach (var user in _allUsers.OrderByDescending(u => u.CreatedAt)) { var points = _loyalty.FirstOrDefault(l => l.UserId == user.Id)?.RawValue ?? 0; var books = _activeReaders.FirstOrDefault(r => r.UserId == user.Id)?.RawValue ?? 0; }
Member Joined Date Lifetime Points Books Read
@(user.FullName?.Substring(0, Math.Min(2, user.FullName.Length)).ToUpper() ?? "U")

@user.FullName

@user.CreatedAt.ToString("MMM dd, yyyy") @points.ToString("N0") @books.ToString("N0")
}
@code { private bool _isLoading = true; private List _subscribers = new(); private List _loyalty = new(); private List _activeReaders = new(); private List _allUsers = new(); private int _totalMembers = 0; private int _activeSubscriptions = 0; protected override async Task OnInitializedAsync() { await LoadInsightsAsync(); } private async Task LoadInsightsAsync() { _isLoading = true; try { var users = await ApiClient.GetUsersAsync(); _allUsers = users.ToList(); _totalMembers = _allUsers.Count; var borrowings = await ApiClient.GetAllBorrowingsAsync(); var subscriptions = await ApiClient.GetAllSubscriptionsAsync(); var memberships = await ApiClient.GetMembershipsAsync(); var loyaltyHistory = await ApiClient.GetAllMembersPointsHistoryAsync(); _activeSubscriptions = subscriptions.Count(s => s.IsActive); // 1. Top Subscribers (Total Spent) var membershipPriceMap = memberships.ToDictionary(m => m.Id, m => m.Price); _subscribers = subscriptions .GroupBy(s => s.UserId) .Select(g => { var user = _allUsers.FirstOrDefault(u => u.Id == g.Key); var totalSpent = g.Sum(s => membershipPriceMap.TryGetValue(s.MembershipId, out var price) ? price : 0); return new InsightItem { UserId = g.Key, Name = user?.FullName ?? "Unknown User", RawValue = (double)totalSpent, ValueLabel = $"MMK {totalSpent:N0}" }; }) .OrderByDescending(i => i.RawValue) .ToList(); // 2. Top Loyalty (Earned Points only) _loyalty = loyaltyHistory .Select(lh => { var user = _allUsers.FirstOrDefault(u => u.Id == lh.UserId); var totalEarned = lh.History.Where(h => h.PointDelta > 0).Sum(h => h.PointDelta); return new InsightItem { UserId = lh.UserId, Name = user?.FullName ?? lh.UserName, RawValue = totalEarned, ValueLabel = $"{totalEarned:N0} pts" }; }) .OrderByDescending(i => i.RawValue) .ToList(); // 3. Most Active (Approved Returns only) _activeReaders = borrowings .Where(b => b.Status == "Returned") .GroupBy(b => b.UserId) .Select(g => { var user = _allUsers.FirstOrDefault(u => u.Id == g.Key); var count = g.Count(); return new InsightItem { UserId = g.Key, Name = user?.FullName ?? "Unknown User", RawValue = count, ValueLabel = $"{count} books" }; }) .OrderByDescending(i => i.RawValue) .ToList(); } catch (Exception ex) { Console.WriteLine($"Error loading insights: {ex.Message}"); } finally { _isLoading = false; } } private class InsightItem { public Guid UserId { get; set; } public string Name { get; set; } = ""; public double RawValue { get; set; } public string ValueLabel { get; set; } = ""; } }