diff --git a/TaxBaik.Web/Components/Admin/Pages/Dashboard.razor b/TaxBaik.Web/Components/Admin/Pages/Dashboard.razor index fe22048..643f3f8 100644 --- a/TaxBaik.Web/Components/Admin/Pages/Dashboard.razor +++ b/TaxBaik.Web/Components/Admin/Pages/Dashboard.razor @@ -1,8 +1,7 @@ @page "/admin/dashboard" @attribute [Authorize] -@using TaxBaik.Application.Services -@inject AdminDashboardService DashboardService -@inject TaxFilingService FilingService +@using TaxBaik.Web.Services +@inject IAdminDashboardClient DashboardClient @inject NavigationManager Nav 대시보드 @@ -161,14 +160,30 @@ @code { private AdminDashboardSummary summary = new(0, 0, 0, 0, []); private List upcomingFilings = []; + private string? errorMessage; + private bool isLoading = true; protected override async Task OnInitializedAsync() { - var summaryTask = DashboardService.GetSummaryAsync(); - var filingsTask = FilingService.GetUpcomingAsync(30); - await Task.WhenAll(summaryTask, filingsTask); - summary = await summaryTask; - upcomingFilings = (await filingsTask).ToList(); + try + { + // API 클라이언트 사용 (서비스 직접 호출 X) + var summaryTask = DashboardClient.GetSummaryAsync(); + var filingsTask = DashboardClient.GetUpcomingFilingsAsync(30); + + await Task.WhenAll(summaryTask, filingsTask); + summary = await summaryTask; + upcomingFilings = (await filingsTask).ToList(); + } + catch (Exception ex) + { + errorMessage = "대시보드 데이터를 불러올 수 없습니다."; + Console.Error.WriteLine($"Dashboard error: {ex.Message}"); + } + finally + { + isLoading = false; + } } private static string GetStatusLabel(string status) => InquiryStatusMapper.Labels.GetValueOrDefault(status, status); diff --git a/TaxBaik.Web/Program.cs b/TaxBaik.Web/Program.cs index 26808e9..bbecbcd 100644 --- a/TaxBaik.Web/Program.cs +++ b/TaxBaik.Web/Program.cs @@ -68,6 +68,7 @@ builder.Services.AddAuthorizationCore(); // HTTP Client for API builder.Services.AddHttpClient(); +builder.Services.AddHttpClient(); // UI & 캐시 builder.Services.AddMudServices(); diff --git a/TaxBaik.Web/Services/AdminDashboardClient.cs b/TaxBaik.Web/Services/AdminDashboardClient.cs new file mode 100644 index 0000000..8950692 --- /dev/null +++ b/TaxBaik.Web/Services/AdminDashboardClient.cs @@ -0,0 +1,105 @@ +using System.Net.Http.Json; +using TaxBaik.Application.Services; +using TaxBaik.Domain.Entities; + +namespace TaxBaik.Web.Services; + +/// +/// Admin Dashboard API Client +/// SOLID: Single Responsibility - Dashboard API 호출만 담당 +/// Dependency Inversion - 추상화된 인터페이스 사용 +/// +public interface IAdminDashboardClient +{ + Task GetSummaryAsync(CancellationToken ct = default); + Task> GetUpcomingFilingsAsync(int days = 30, CancellationToken ct = default); + Task> GetRecentInquiriesAsync(int limit = 10, CancellationToken ct = default); + Task GetMonthlyStatsAsync(string? month = null, CancellationToken ct = default); +} + +public class AdminDashboardClient : IAdminDashboardClient +{ + private readonly HttpClient _http; + private readonly ILogger _logger; + + public AdminDashboardClient(HttpClient http, ILogger logger) + { + _http = http; + _logger = logger; + _http.BaseAddress = new Uri("/taxbaik/api/"); + } + + public async Task GetSummaryAsync(CancellationToken ct = default) + { + try + { + var result = await _http.GetFromJsonAsync( + "admin-dashboard/summary", cancellationToken: ct); + return result ?? new(0, 0, 0, 0, []); + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Failed to fetch dashboard summary"); + throw; + } + } + + public async Task> GetUpcomingFilingsAsync(int days = 30, CancellationToken ct = default) + { + try + { + var result = await _http.GetFromJsonAsync>( + $"admin-dashboard/upcoming-filings?days={days}", cancellationToken: ct); + return result?.Data ?? []; + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Failed to fetch upcoming filings"); + throw; + } + } + + public async Task> GetRecentInquiriesAsync(int limit = 10, CancellationToken ct = default) + { + try + { + var result = await _http.GetFromJsonAsync>( + $"admin-dashboard/recent-inquiries?limit={limit}", cancellationToken: ct); + return result?.Data ?? []; + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Failed to fetch recent inquiries"); + throw; + } + } + + public async Task GetMonthlyStatsAsync(string? month = null, CancellationToken ct = default) + { + try + { + var url = "admin-dashboard/monthly-stats"; + if (!string.IsNullOrEmpty(month)) + url += $"?month={month}"; + + var result = await _http.GetFromJsonAsync(url, cancellationToken: ct); + return result ?? new(); + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Failed to fetch monthly stats"); + throw; + } + } +} + +/// +/// API Response wrapper +/// +internal class ApiResponse +{ + public IEnumerable? Data { get; set; } + public int Total { get; set; } + public int Page { get; set; } + public int PageSize { get; set; } +}