@page "/Membership" @using BlazorFrontend.Services @using LibraryManagement.Shared.Models @using BlazorFrontend.Models @inject LibraryApiClient ApiClient @inject IJSRuntime JSRuntime @inject NavigationManager Navigation My Membership @if (_isLoading) {
} else if (_viewModel != null) { var hasActiveSub = _viewModel.CurrentSubscription != null && _viewModel.CurrentSubscription.IsActive;

Membership

Manage your subscription and library benefits

@if (_viewModel.LoyaltyAccount != null) {
Available Points
@_viewModel.LoyaltyAccount.CurrentBalance.ToString("N0")
}
Wallet Balance
@_viewModel.WalletBalance.ToString("N0") MMK

Active Plan

@if (hasActiveSub && _viewModel.CurrentSubscription != null) {
Active Status

@_viewModel.CurrentSubscription.MembershipType

Start Date
@_viewModel.CurrentSubscription.StartDate.ToString("MMM dd, yyyy")
Expiry Date
@_viewModel.CurrentSubscription.ExpiryDate.ToString("MMM dd, yyyy")
Pro-tip: Maintain your subscription to earn loyalty points every month!
} else {

No Active Subscription

Get a membership to borrow books and unlock premium library features.

Browse Plans
}
@if (_viewModel.QueuedMemberships.Any()) {

Queued Memberships (@_viewModel.QueuedMemberships.Count)

@foreach (var queued in _viewModel.QueuedMemberships) {
@queued.MembershipType Membership
Activates on @queued.StartDate.ToString("MMM dd, yyyy") • Expires @queued.ExpiryDate.ToString("MMM dd, yyyy")
Queued
Will activate automatically
}
}

Your Benefits

    @{ var currentPlan = _viewModel.AvailableMemberships.FirstOrDefault(m => hasActiveSub && _viewModel.CurrentSubscription != null && m.Type == _viewModel.CurrentSubscription.MembershipType); }
  • @((currentPlan?.MaxBooks ?? 1))
    Max Books
    Number of books you can borrow simultaneously.
  • @((currentPlan?.BorrowingDays ?? 14))
    Borrowing Days
    Duration you can keep each borrowed book.
  • Digital Access
    Browse and search the full library catalog online.

Want more books?

Upgrade Plan →

Explore Membership Plans

Find the perfect library experience for your reading habits

@foreach (var plan in _viewModel.AvailableMemberships) { var isCurrent = hasActiveSub && _viewModel.CurrentSubscription != null && plan.Type == _viewModel.CurrentSubscription.MembershipType;
@if (isCurrent) {
Current Plan
}

@plan.Type

@plan.Price.ToString("N0") MMK
/ @(plan.DurationMonths == 1 ? "Month" : $"{plan.DurationMonths} Months")
  • @plan.MaxBooks Books limit
  • @plan.BorrowingDays Days keep
  • @if (!string.IsNullOrEmpty(plan.RewardId) && _viewModel.RewardPointCosts.TryGetValue(plan.RewardId, out var pointCost)) {
  • @pointCost.ToString("N0") Points
  • }
@if (isCurrent) { } else {
Pay Cash @if (!string.IsNullOrEmpty(plan.RewardId) && _viewModel.RewardPointCosts.ContainsKey(plan.RewardId)) { }
}
}
} @code { private MembershipViewModel? _viewModel; private bool _isLoading = true; protected override async Task OnInitializedAsync() { try { var allSubscriptions = await ApiClient.GetMyAllSubscriptionsAsync(); var memberships = await ApiClient.GetMembershipsAsync(); var loyaltyAccount = await ApiClient.GetMyLoyaltyAccountAsync(); var activeRewards = await ApiClient.GetActiveRewardsAsync(); var now = DateTime.UtcNow; var currentSubscription = allSubscriptions .Where(s => s.StartDate <= now && s.ExpiryDate > now) .OrderByDescending(s => s.StartDate) .FirstOrDefault(); var queuedMemberships = allSubscriptions .Where(s => s.StartDate > now) .OrderBy(s => s.StartDate) .ToList(); _viewModel = new MembershipViewModel { CurrentSubscription = currentSubscription, AvailableMemberships = memberships.ToList(), QueuedMemberships = queuedMemberships, LoyaltyAccount = loyaltyAccount, RewardPointCosts = activeRewards.ToDictionary(r => r.Id, r => r.PointCost), WalletBalance = await ApiClient.GetWalletBalanceAsync() }; } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("showToast", "Error loading membership data: " + ex.Message, "error"); } finally { _isLoading = false; } } private async Task RedeemMembership(string rewardId, string planName, double cost) { bool confirmed = await JSRuntime.InvokeAsync("confirm", $"Are you sure you want to redeem {planName} for {cost:N0} points?"); if (!confirmed) return; try { var (success, message) = await ApiClient.ClaimRewardAsync(rewardId, "Redeemed via Library Membership Page"); if (success) { await JSRuntime.InvokeVoidAsync("showToast", message, "success"); await OnInitializedAsync(); // Refresh data } else { await JSRuntime.InvokeVoidAsync("showToast", "Error: " + message, "error"); } } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("showToast", "An unexpected error occurred: " + ex.Message, "error"); } } private async Task BuyWithWallet(MembershipDto plan) { try { var preview = await ApiClient.GetUpgradePreviewAsync(plan.Id); if (preview == null || !preview.CanUpgrade) { await JSRuntime.InvokeVoidAsync("showToast", preview?.Message ?? "Cannot upgrade to this plan.", "error"); return; } string confirmMsg = $"Are you sure you want to purchase {plan.Type} membership?\n\n" + $"Original Price: {preview.OriginalPrice:N0} MMK\n"; if (preview.DiscountAmount > 0) { confirmMsg += $"Upgrade Discount: -{preview.DiscountAmount:N0} MMK\n"; } confirmMsg += $"Final Price: {preview.FinalPrice:N0} MMK\n\n" + $"Your Balance: {_viewModel?.WalletBalance:N0} MMK"; bool confirmed = await JSRuntime.InvokeAsync("confirm", confirmMsg); if (!confirmed) return; if (_viewModel?.WalletBalance < preview.FinalPrice) { await JSRuntime.InvokeVoidAsync("showToast", "Insufficient wallet balance. Please top up at the library.", "error"); return; } var result = await ApiClient.SubscribeWithWalletAsync(new SubscribeRequest { MembershipId = plan.Id }); if (result != null) { await JSRuntime.InvokeVoidAsync("showToast", "Subscription purchased successfully!", "success"); await OnInitializedAsync(); } else { await JSRuntime.InvokeVoidAsync("showToast", "Failed to complete purchase.", "error"); } } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("showToast", "Error: " + ex.Message, "error"); } } }