@page "/Insights" @using BlazorFrontend.Services @using LibraryManagement.Shared.Models @using Microsoft.AspNetCore.Authorization @attribute [Authorize(Roles = "Librarian")] @inject LibraryApiClient ApiClient User Insights

User Insights

Discover top-performing library members and engagement trends.

@if (_isLoading) {

Calculating insights...

} else {
@if (CurrentInsightData.Any()) {
@* 2nd Place *@ @if (CurrentInsightData.Count() > 1) { var user = CurrentInsightData.ElementAt(1);
@(user.Name.Substring(0, Math.Min(2, user.Name.Length)).ToUpper())
2

@user.Name

@user.ValueLabel

} @* 1st Place *@ @if (CurrentInsightData.Any()) { var user = CurrentInsightData.ElementAt(0);
@(user.Name.Substring(0, Math.Min(2, user.Name.Length)).ToUpper())
1

@user.Name

@user.ValueLabel

} @* 3rd Place *@ @if (CurrentInsightData.Count() > 2) { var user = CurrentInsightData.ElementAt(2);
@(user.Name.Substring(0, Math.Min(2, user.Name.Length)).ToUpper())
3

@user.Name

@user.ValueLabel

}

Rankings Overview

@foreach (var (user, index) in CurrentInsightData.Select((u, i) => (u, i))) { }
Rank Member Performance Progress
#@(index + 1)
@(user.Name.Substring(0, Math.Min(2, user.Name.Length)).ToUpper())

@user.Name

Member since @user.JoinedDate.ToString("MMM yyyy")

@user.ValueLabel Lifetime Achievement
} else {

No data available for this insight yet.

}
} @code { private bool _isLoading = true; private string _activeTab = "Subscribers"; private List _subscribers = new(); private List _loyalty = new(); private List _activeReaders = new(); private IEnumerable CurrentInsightData => _activeTab switch { "Subscribers" => _subscribers, "Loyalty" => _loyalty, "Active" => _activeReaders, _ => Enumerable.Empty() }; protected override async Task OnInitializedAsync() { await LoadInsightsAsync(); } private async Task LoadInsightsAsync() { _isLoading = true; try { var users = await ApiClient.GetUsersAsync(); var borrowings = await ApiClient.GetAllBorrowingsAsync(); var subscriptions = await ApiClient.GetAllSubscriptionsAsync(); var memberships = await ApiClient.GetMembershipsAsync(); var loyaltyHistory = await ApiClient.GetAllMembersPointsHistoryAsync(); // 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 = users.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", JoinedDate = user?.CreatedAt ?? DateTime.MinValue, RawValue = (double)totalSpent, ValueLabel = $"MMK {totalSpent:N0}" }; }) .OrderByDescending(i => i.RawValue) .ToList(); // 2. Top Loyalty (Earned Points only) _loyalty = loyaltyHistory .Select(lh => { var user = users.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, JoinedDate = user?.CreatedAt ?? DateTime.MinValue, RawValue = totalEarned, ValueLabel = $"{totalEarned:N0} Points" }; }) .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 = users.FirstOrDefault(u => u.Id == g.Key); var count = g.Count(); return new InsightItem { UserId = g.Key, Name = user?.FullName ?? "Unknown User", JoinedDate = user?.CreatedAt ?? DateTime.MinValue, RawValue = count, ValueLabel = $"{count} Completed" }; }) .OrderByDescending(i => i.RawValue) .ToList(); } catch (Exception ex) { Console.WriteLine($"Error loading insights: {ex.Message}"); } finally { _isLoading = false; } } private double CalculatePercentage(double value) { var max = CurrentInsightData.Any() ? CurrentInsightData.Max(i => i.RawValue) : 1; if (max == 0) return 0; return (value / max) * 100; } private class InsightItem { public Guid UserId { get; set; } public string Name { get; set; } = ""; public DateTime JoinedDate { get; set; } public double RawValue { get; set; } public string ValueLabel { get; set; } = ""; } }