LibraryManagement / BlazorFrontend /Services /LibraryApiClient.cs
Yuyuqt
add: user balance
ee79726
Raw
History Blame Contribute Delete
19.8 kB
using System.Text.Json.Serialization;
using System.Net.Http.Json;
using System.Text.Json;
using LibraryManagement.Shared.Models;
namespace BlazorFrontend.Services
{
public class LibraryApiClient
{
private readonly HttpClient _httpClient;
public LibraryApiClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
// Note: You do NOT need to call a SetToken method anymore!
// Because we registered AuthHeaderHandler in Program.cs as a DelegatingHandler for "LibraryBackend",
// the JWT token is automatically injected into the headers of EVERY single request made by _httpClient.
#region Auth
public async Task<AuthResponse?> LoginAsync(LoginRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/auth/login", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<AuthResponse>() : null;
}
public async Task<AuthResponse?> RegisterAsync(RegisterRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/auth/register", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<AuthResponse>() : null;
}
public async Task<object?> GetProfileAsync()
{
return await _httpClient.GetFromJsonAsync<object>("api/auth/me");
}
#endregion
#region Books
public async Task<IEnumerable<BookDto>> GetBooksAsync(int? categoryId = null)
{
var url = categoryId.HasValue ? $"api/books?categoryId={categoryId}" : "api/books";
return await _httpClient.GetFromJsonAsync<IEnumerable<BookDto>>(url) ?? Enumerable.Empty<BookDto>();
}
public async Task<BookDto?> GetBookAsync(int id)
{
return await _httpClient.GetFromJsonAsync<BookDto>($"api/books/{id}");
}
public async Task<List<BookDto>> GetBooksByIdsAsync(List<int> ids)
{
if (ids == null || !ids.Any()) return new List<BookDto>();
var idsStr = string.Join(",", ids);
return await _httpClient.GetFromJsonAsync<List<BookDto>>($"api/books/by-ids?ids={idsStr}") ?? new List<BookDto>();
}
public async Task<BookDto?> CreateBookAsync(BookCreateRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/books", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<BookDto>() : null;
}
public async Task<BookDto?> UpdateBookAsync(int id, BookUpdateRequest request)
{
var response = await _httpClient.PutAsJsonAsync($"api/books/{id}", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<BookDto>() : null;
}
public async Task<bool> DeleteBookAsync(int id)
{
var response = await _httpClient.DeleteAsync($"api/books/{id}");
return response.IsSuccessStatusCode;
}
#endregion
#region Borrowings
public async Task<BorrowingDto?> BorrowBookAsync(BorrowRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/borrowings/borrow", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<BorrowingDto>() : null;
}
public async Task<BorrowingDto?> ReturnBookAsync(Guid id)
{
var response = await _httpClient.PostAsync($"api/borrowings/return/{id}", null);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<BorrowingDto>() : null;
}
public async Task<IEnumerable<BorrowingDto>> GetMyBorrowingsAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<BorrowingDto>>("api/borrowings/me") ?? Enumerable.Empty<BorrowingDto>();
}
public async Task<IEnumerable<BorrowingDto>> GetAllBorrowingsAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<BorrowingDto>>("api/borrowings") ?? Enumerable.Empty<BorrowingDto>();
}
#endregion
#region Categories
public async Task<IEnumerable<CategoryDto>> GetCategoriesAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<CategoryDto>>("api/categories") ?? Enumerable.Empty<CategoryDto>();
}
public async Task<IEnumerable<CategoryDto>> GetCategoriesWithBooksAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<CategoryDto>>("api/categories/with-books") ?? Enumerable.Empty<CategoryDto>();
}
public async Task<CategoryDto?> CreateCategoryAsync(CategoryCreateRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/categories", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<CategoryDto>() : null;
}
public async Task<bool> DeleteCategoryAsync(int id)
{
var response = await _httpClient.DeleteAsync($"api/categories/{id}");
return response.IsSuccessStatusCode;
}
#endregion
#region Subscriptions
public async Task<IEnumerable<MembershipDto>> GetMembershipsAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<MembershipDto>>("api/memberships") ?? Enumerable.Empty<MembershipDto>();
}
public async Task<SubscriptionDto?> GetMySubscriptionAsync()
{
try
{
return await _httpClient.GetFromJsonAsync<SubscriptionDto>("api/subscriptions/me");
}
catch { return null; }
}
public async Task<IEnumerable<SubscriptionDto>> GetMyAllSubscriptionsAsync()
{
try
{
return await _httpClient.GetFromJsonAsync<IEnumerable<SubscriptionDto>>("api/subscriptions/me/all") ?? Enumerable.Empty<SubscriptionDto>();
}
catch { return Enumerable.Empty<SubscriptionDto>(); }
}
public async Task<SubscriptionDto?> SubscribeAsync(SubscribeRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/subscriptions/subscribe", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<SubscriptionDto>() : null;
}
public async Task<SubscriptionDto?> GetUserSubscriptionAsync(Guid userId)
{
try
{
return await _httpClient.GetFromJsonAsync<SubscriptionDto>($"api/subscriptions/user/{userId}");
}
catch { return null; }
}
public async Task<SubscriptionDto?> AdminSubscribeAsync(AdminSubscribeRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/subscriptions/admin-subscribe", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<SubscriptionDto>() : null;
}
public async Task<IEnumerable<SubscriptionDto>> GetAllSubscriptionsAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<SubscriptionDto>>("api/subscriptions/all") ?? Enumerable.Empty<SubscriptionDto>();
}
public async Task<SubscriptionUpgradePreviewDto?> GetUpgradePreviewAsync(int membershipId)
{
try
{
return await _httpClient.GetFromJsonAsync<SubscriptionUpgradePreviewDto>($"api/subscriptions/preview-upgrade/{membershipId}");
}
catch { return null; }
}
public async Task<SubscriptionDto?> SubscribeWithWalletAsync(SubscribeRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/subscriptions/subscribe-wallet", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<SubscriptionDto>() : null;
}
#endregion
#region Wallet
public async Task<decimal> GetWalletBalanceAsync()
{
try
{
return await _httpClient.GetFromJsonAsync<decimal>("api/wallet/balance");
}
catch { return 0; }
}
public async Task<IEnumerable<WalletTransactionDto>> GetWalletHistoryAsync()
{
try
{
return await _httpClient.GetFromJsonAsync<IEnumerable<WalletTransactionDto>>("api/wallet/history") ?? Enumerable.Empty<WalletTransactionDto>();
}
catch { return Enumerable.Empty<WalletTransactionDto>(); }
}
public async Task<bool> TopUpWalletAsync(TopUpRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/wallet/topup", request);
return response.IsSuccessStatusCode;
}
#endregion
public async Task<LoyaltyAccountDto?> GetMyLoyaltyAccountAsync()
{
try
{
// Using exact casing for the route to be safe
var response = await _httpClient.GetAsync("api/Loyalty/my-account");
if (response.IsSuccessStatusCode)
{
// JsonPropertyName attributes in LoyaltyAccountDto will handle the mapping
// and correctly populate CurrentBalance from the backend's currentBalance
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString }; return await response.Content.ReadFromJsonAsync<LoyaltyAccountDto>(options);
}
else
{
var error = await response.Content.ReadAsStringAsync();
System.Diagnostics.Debug.WriteLine($"Loyalty API error: {response.StatusCode} - {error}");
// Throw custom exception or return null based on error
}
return null;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Loyalty API Exception: {ex.Message}");
return null;
}
}
public async Task<IEnumerable<LoyaltyRedemptionDto>> GetMyRedemptionsAsync()
{
try
{
return await _httpClient.GetFromJsonAsync<IEnumerable<LoyaltyRedemptionDto>>("api/Loyalty/my-redemptions") ?? Enumerable.Empty<LoyaltyRedemptionDto>();
}
catch { return Enumerable.Empty<LoyaltyRedemptionDto>(); }
}
public async Task<IEnumerable<LoyaltyRedemptionDto>> GetMyPendingRedemptionsAsync()
{
try
{
return await _httpClient.GetFromJsonAsync<IEnumerable<LoyaltyRedemptionDto>>("api/Loyalty/my-pending-redemptions") ?? Enumerable.Empty<LoyaltyRedemptionDto>();
}
catch { return Enumerable.Empty<LoyaltyRedemptionDto>(); }
}
public async Task<IEnumerable<PointHistoryEntryDto>> GetPointsHistoryAsync(string accountId)
{
try
{
// Call the Backend's proxy endpoint instead of trying to hit the external API directly
return await _httpClient.GetFromJsonAsync<IEnumerable<PointHistoryEntryDto>>("api/Loyalty/my-points-history") ?? Enumerable.Empty<PointHistoryEntryDto>();
}
catch { return Enumerable.Empty<PointHistoryEntryDto>(); }
}
public async Task<IEnumerable<UserPointsHistoryDto>> GetAllMembersPointsHistoryAsync()
{
try {
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
var response = await _httpClient.GetAsync("api/Loyalty/admin/all-points-history");
var raw = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
return Enumerable.Empty<UserPointsHistoryDto>();
var data = JsonSerializer.Deserialize<List<UserPointsHistoryDto>>(raw, options) ?? new List<UserPointsHistoryDto>();
foreach (var member in data)
{
member.History = member.History?.ToList() ?? new List<PointHistoryEntryDto>();
member.Redemptions = member.Redemptions?.ToList() ?? new List<LoyaltyRedemptionDto>();
}
return data;
} catch { return Enumerable.Empty<UserPointsHistoryDto>(); }
}
public async Task<bool> RequestReturnAsync(Guid borrowingId)
{
var response = await _httpClient.PostAsync($"api/borrowings/return-request/{borrowingId}", null);
return response.IsSuccessStatusCode;
}
public async Task<(bool Success, string Message)> ClaimRewardAsync(string rewardId, string? notes = null)
{
try
{
var request = new ClaimRewardRequestDto { RewardId = rewardId, Notes = notes };
var response = await _httpClient.PostAsJsonAsync("api/Loyalty/claim", request);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadFromJsonAsync<JsonDocument>();
string msg = "Reward claimed successfully!";
if (result != null && result.RootElement.TryGetProperty("message", out var msgElement))
{
msg = msgElement.GetString() ?? msg;
}
return (true, msg);
}
else
{
var error = await response.Content.ReadFromJsonAsync<JsonDocument>();
string msg = "Failed to claim reward.";
if (error != null && error.RootElement.TryGetProperty("message", out var msgElement))
{
msg = msgElement.GetString() ?? msg;
}
return (false, msg);
}
}
catch (Exception ex)
{
return (false, $"An error occurred: {ex.Message}");
}
}
public async Task<IEnumerable<LoyaltyRewardDto>> GetActiveRewardsAsync()
{
try
{
// Call our Backend proxy which handles the external API and SystemId
return await _httpClient.GetFromJsonAsync<IEnumerable<LoyaltyRewardDto>>("api/Loyalty/rewards") ?? Enumerable.Empty<LoyaltyRewardDto>();
}
catch { return Enumerable.Empty<LoyaltyRewardDto>(); }
}
#region Users
public async Task<IEnumerable<UserDto>> GetUsersAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<UserDto>>("api/users") ?? Enumerable.Empty<UserDto>();
}
public async Task<UserDto?> GetUserAsync(Guid id)
{
return await _httpClient.GetFromJsonAsync<UserDto>($"api/users/{id}");
}
public async Task<UserDto?> CreateUserAsync(UserCreateRequest request)
{
var response = await _httpClient.PostAsJsonAsync("api/users", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<UserDto>() : null;
}
public async Task<UserDto?> UpdateUserAsync(Guid id, UserUpdateRequest request)
{
var response = await _httpClient.PutAsJsonAsync($"api/users/{id}", request);
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<UserDto>() : null;
}
public async Task<bool> UpdateUserRoleAsync(Guid id, string role)
{
var response = await _httpClient.PutAsJsonAsync($"api/users/role/{id}", new UserRoleUpdateRequest { Role = role });
return response.IsSuccessStatusCode;
}
public async Task<bool> DeleteUserAsync(Guid id)
{
var response = await _httpClient.DeleteAsync($"api/users/{id}");
return response.IsSuccessStatusCode;
}
#endregion
public async Task<IEnumerable<LoyaltyRedemptionDto>> GetPendingRedemptionsAsync()
{
try
{
var response = await _httpClient.GetAsync("api/Loyalty/admin/redemptions/pending");
if (response.IsSuccessStatusCode)
{
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
return await response.Content.ReadFromJsonAsync<IEnumerable<LoyaltyRedemptionDto>>(options) ?? Enumerable.Empty<LoyaltyRedemptionDto>();
}
return Enumerable.Empty<LoyaltyRedemptionDto>();
}
catch { return Enumerable.Empty<LoyaltyRedemptionDto>(); }
}
public async Task<(bool Success, string Message)> FulfillRedemptionAsync(string id)
{
try
{
var response = await _httpClient.PostAsync($"api/Loyalty/admin/redemptions/{id}/fulfill", null);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadFromJsonAsync<JsonDocument>();
string msg = "Redemption fulfilled successfully!";
if (result != null && result.RootElement.TryGetProperty("message", out var msgElement))
{
msg = msgElement.GetString() ?? msg;
}
return (true, msg);
}
else
{
var error = await response.Content.ReadFromJsonAsync<JsonDocument>();
string msg = "Failed to fulfill redemption.";
if (error != null && error.RootElement.TryGetProperty("message", out var msgElement))
{
msg = msgElement.GetString() ?? msg;
}
return (false, msg);
}
}
catch (Exception ex) { return (false, $"Error: {ex.Message}"); }
}
#region Notifications
public async Task<IEnumerable<NotificationDto>> GetNotificationsAsync()
{
return await _httpClient.GetFromJsonAsync<IEnumerable<NotificationDto>>("api/notifications") ?? Enumerable.Empty<NotificationDto>();
}
public async Task<int> GetUnreadNotificationCountAsync()
{
try
{
return await _httpClient.GetFromJsonAsync<int>("api/notifications/unread-count");
}
catch { return 0; }
}
public async Task<bool> MarkNotificationsReadAsync()
{
var response = await _httpClient.PostAsJsonAsync("api/notifications/mark-read", new { });
return response.IsSuccessStatusCode;
}
public async Task<bool> UpdateFcmTokenAsync(string fcmToken)
{
var response = await _httpClient.PostAsJsonAsync("api/users/fcm-token", new { fcmToken });
return response.IsSuccessStatusCode;
}
public async Task<bool> SyncWishlistAsync(List<int> bookIds)
{
var response = await _httpClient.PostAsJsonAsync("api/wishlist/sync", bookIds);
return response.IsSuccessStatusCode;
}
#endregion
}
}