This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.9" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.9" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.9" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.9" />
|
||||||
<PackageReference Include="MudBlazor" Version="6.10.0" />
|
<PackageReference Include="MudBlazor" Version="9.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<p>로드 중...</p>
|
<p>로드 중...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Routes @rendermode="InteractiveWebAssembly" />
|
<Routes @rendermode="@(new InteractiveWebAssemblyRenderMode(prerender: false))" />
|
||||||
<script src="/taxbaik/_content/MudBlazor/MudBlazor.min.js"></script>
|
<script src="/taxbaik/_content/MudBlazor/MudBlazor.min.js"></script>
|
||||||
<script src="/taxbaik/js/admin-session.js"></script>
|
<script src="/taxbaik/js/admin-session.js"></script>
|
||||||
<script src="/taxbaik/admin/_framework/blazor.webassembly.js"></script>
|
<script src="/taxbaik/admin/_framework/blazor.webassembly.js"></script>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</MudDialog>
|
</MudDialog>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[CascadingParameter] MudDialogInstance? MudDialog { get; set; }
|
[CascadingParameter] IMudDialogInstance? MudDialog { get; set; }
|
||||||
|
|
||||||
void Cancel() => MudDialog?.Cancel();
|
void Cancel() => MudDialog?.Cancel();
|
||||||
void Confirm() => MudDialog?.Close(DialogResult.Ok(true));
|
void Confirm() => MudDialog?.Close(DialogResult.Ok(true));
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<MudTextField @bind-Value="model.Memo" Label="메모"
|
<MudTextField @bind-Value="model.Memo" Label="메모"
|
||||||
Variant="Variant.Outlined" Lines="3" Class="mb-4" />
|
Variant="Variant.Outlined" Lines="3" Class="mb-4" />
|
||||||
|
|
||||||
<MudCheckBox @bind-Checked="model.IsActive" Label="활성" Class="mb-4" />
|
<MudCheckBox T="bool" @bind-Value="model.IsActive" Label="활성" Class="mb-4" />
|
||||||
|
|
||||||
<div class="d-flex gap-2">
|
<div class="d-flex gap-2">
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" @onclick="HandleSubmit">
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" @onclick="HandleSubmit">
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
if (form == null)
|
if (form == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!form.IsValid)
|
if (!form.IsValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
if (form == null)
|
if (form == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!form.IsValid)
|
if (!form.IsValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<td>@inquiry.Phone</td>
|
<td>@inquiry.Phone</td>
|
||||||
<td>@inquiry.ServiceType</td>
|
<td>@inquiry.ServiceType</td>
|
||||||
<td>
|
<td>
|
||||||
<MudChip Size="Size.Small" Color="@GetStatusColor(inquiry.Status)">
|
<MudChip T="string" Size="Size.Small" Color="@GetStatusColor(inquiry.Status)">
|
||||||
@GetStatusLabel(inquiry.Status)
|
@GetStatusLabel(inquiry.Status)
|
||||||
</MudChip>
|
</MudChip>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
<MudThemeProvider />
|
||||||
|
<MudPopoverProvider />
|
||||||
|
<MudDialogProvider />
|
||||||
|
<MudSnackbarProvider />
|
||||||
|
|
||||||
<AdminShell>
|
<AdminShell>
|
||||||
<AdminTelemetryContext />
|
<AdminTelemetryContext />
|
||||||
@Body
|
@Body
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin"
|
@page "/admin"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@page "/admin/announcements/create"
|
@page "/admin/announcements/create"
|
||||||
@page "/admin/announcements/{Id:int}/edit"
|
@page "/admin/announcements/{Id:int}/edit"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using System.ComponentModel.DataAnnotations
|
@using System.ComponentModel.DataAnnotations
|
||||||
@using TaxBaik.Application.DTOs
|
@using TaxBaik.Application.DTOs
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
</MudItem>
|
</MudItem>
|
||||||
|
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudSwitch @bind-Checked="model.IsActive"
|
<MudSwitch T="bool" @bind-Value="model.IsActive"
|
||||||
Label="@(model.IsActive ? "활성화 (홈페이지에 노출)" : "비활성화 (홈페이지 미노출)")"
|
Label="@(model.IsActive ? "활성화 (홈페이지에 노출)" : "비활성화 (홈페이지 미노출)")"
|
||||||
Color="Color.Primary" />
|
Color="Color.Primary" />
|
||||||
</MudItem>
|
</MudItem>
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
private async Task SaveAsync()
|
private async Task SaveAsync()
|
||||||
{
|
{
|
||||||
if (form is null) return;
|
if (form is null) return;
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!form.IsValid) return;
|
if (!form.IsValid) return;
|
||||||
|
|
||||||
isSaving = true;
|
isSaving = true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/announcements"
|
@page "/admin/announcements"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@using TaxBaik.Domain.Entities
|
@using TaxBaik.Domain.Entities
|
||||||
@@ -58,22 +58,22 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>@item.Title</td>
|
<td>@item.Title</td>
|
||||||
<td>
|
<td>
|
||||||
<MudChip Size="Size.Small" Color="@GetTypeColor(item.DisplayType)">
|
<MudChip T="string" Size="Size.Small" Color="@GetTypeColor(item.DisplayType)">
|
||||||
@GetTypeLabel(item.DisplayType)
|
@GetTypeLabel(item.DisplayType)
|
||||||
</MudChip>
|
</MudChip>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if (IsCurrentlyActive(item))
|
@if (IsCurrentlyActive(item))
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Success">노출 중</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Success">노출 중</MudChip>
|
||||||
}
|
}
|
||||||
else if (!item.IsActive)
|
else if (!item.IsActive)
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Default">비활성</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Default">비활성</MudChip>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Warning">기간 외</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Warning">기간 외</MudChip>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td class="small">
|
<td class="small">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/blog/create"
|
@page "/admin/blog/create"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.DTOs
|
@using TaxBaik.Application.DTOs
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Pages.Blog
|
@using TaxBaik.WasmClient.Components.Admin.Pages.Blog
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/blog/{id:int}/edit"
|
@page "/admin/blog/{id:int}/edit"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.DTOs
|
@using TaxBaik.Application.DTOs
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Pages.Blog
|
@using TaxBaik.WasmClient.Components.Admin.Pages.Blog
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
|
|
||||||
<MudCheckBox @bind-Checked="Model.IsPublished" Label="즉시 발행" Class="mb-4" />
|
<MudCheckBox T="bool" @bind-Value="Model.IsPublished" Label="즉시 발행" Class="mb-4" />
|
||||||
</AdminFormSection>
|
</AdminFormSection>
|
||||||
|
|
||||||
<AdminFormSection Title="본문" Description="SEO와 실제 노출 본문을 함께 관리합니다." CssClass="mb-4">
|
<AdminFormSection Title="본문" Description="SEO와 실제 노출 본문을 함께 관리합니다." CssClass="mb-4">
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
if (form == null)
|
if (form == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!form.IsValid)
|
if (!form.IsValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/blog"
|
@page "/admin/blog"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@inject IBlogBrowserClient BlogClient
|
@inject IBlogBrowserClient BlogClient
|
||||||
@inject ISnackbar Snackbar
|
@inject ISnackbar Snackbar
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
<MudText Typo="Typo.body2">페이지 @currentPage / @totalPages</MudText>
|
<MudText Typo="Typo.body2">페이지 @currentPage / @totalPages</MudText>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
<MudDataGrid Items="@FilteredPosts" Striped="true" Hoverable="true" Class="admin-grid">
|
<MudDataGrid Items="@FilteredPosts" Striped="true" Hover="true" Class="admin-grid">
|
||||||
<Columns>
|
<Columns>
|
||||||
<PropertyColumn Property="x => x.Title" Title="제목" />
|
<PropertyColumn Property="x => x.Title" Title="제목" />
|
||||||
<PropertyColumn Property="x => x.IsPublished" Title="발행">
|
<PropertyColumn Property="x => x.IsPublished" Title="발행">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/clients/{ClientId:int}"
|
@page "/admin/clients/{ClientId:int}"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@using TaxBaik.Web.Services.AdminClients
|
@using TaxBaik.Web.Services.AdminClients
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@page "/admin/clients/create"
|
@page "/admin/clients/create"
|
||||||
@page "/admin/clients/{Id:int}/edit"
|
@page "/admin/clients/{Id:int}/edit"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.DTOs
|
@using TaxBaik.Application.DTOs
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudTextField @bind-Value="dto.Memo" Label="메모"
|
<MudTextField @bind-Value="dto.Memo" Label="메모"
|
||||||
Lines="4" AutoGrow="true"
|
Lines="4"
|
||||||
Placeholder="상담 배경, 특이사항, 중요 날짜 등 자유롭게 기록하세요" />
|
Placeholder="상담 배경, 특이사항, 중요 날짜 등 자유롭게 기록하세요" />
|
||||||
</MudItem>
|
</MudItem>
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
|
|
||||||
private async Task SaveAsync()
|
private async Task SaveAsync()
|
||||||
{
|
{
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!isValid) return;
|
if (!isValid) return;
|
||||||
|
|
||||||
isSaving = true;
|
isSaving = true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/clients"
|
@page "/admin/clients"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@using TaxBaik.Domain.Entities
|
@using TaxBaik.Domain.Entities
|
||||||
@@ -74,18 +74,18 @@
|
|||||||
<td>
|
<td>
|
||||||
@if (!string.IsNullOrEmpty(c.ServiceType))
|
@if (!string.IsNullOrEmpty(c.ServiceType))
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Primary">@c.ServiceType</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Primary">@c.ServiceType</MudChip>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>@(c.TaxType ?? "—")</td>
|
<td>@(c.TaxType ?? "—")</td>
|
||||||
<td>
|
<td>
|
||||||
@if (c.Status == "active")
|
@if (c.Status == "active")
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Success">활성</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Success">활성</MudChip>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Default">비활성</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Default">비활성</MudChip>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>@(c.Source ?? "—")</td>
|
<td>@(c.Source ?? "—")</td>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/common-codes"
|
@page "/admin/common-codes"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@using TaxBaik.Web.Services.AdminClients
|
@using TaxBaik.Web.Services.AdminClients
|
||||||
@using TaxBaik.Domain.Entities
|
@using TaxBaik.Domain.Entities
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/companies/create"
|
@page "/admin/companies/create"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Forms
|
@using TaxBaik.WasmClient.Components.Admin.Forms
|
||||||
@inject IApiClient ApiClient
|
@inject IApiClient ApiClient
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/companies/{id:int}/edit"
|
@page "/admin/companies/{id:int}/edit"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Forms
|
@using TaxBaik.WasmClient.Components.Admin.Forms
|
||||||
@inject IApiClient ApiClient
|
@inject IApiClient ApiClient
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/companies"
|
@page "/admin/companies"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@inject IApiClient ApiClient
|
@inject IApiClient ApiClient
|
||||||
@inject ISnackbar Snackbar
|
@inject ISnackbar Snackbar
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</MudStack>
|
</MudStack>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
|
||||||
<MudDataGrid Items="@companies" Striped="true" Hoverable="true" Loading="@isLoading" Class="admin-grid">
|
<MudDataGrid Items="@companies" Striped="true" Hover="true" Loading="@isLoading" Class="admin-grid">
|
||||||
<Columns>
|
<Columns>
|
||||||
<PropertyColumn Property="x => x.CompanyCode" Title="회사코드" />
|
<PropertyColumn Property="x => x.CompanyCode" Title="회사코드" />
|
||||||
<PropertyColumn Property="x => x.CompanyName" Title="회사명" />
|
<PropertyColumn Property="x => x.CompanyName" Title="회사명" />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/consulting-activities"
|
@page "/admin/consulting-activities"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@using TaxBaik.Web.Services.AdminClients
|
@using TaxBaik.Web.Services.AdminClients
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Shared
|
@using TaxBaik.WasmClient.Components.Admin.Shared
|
||||||
@inject IConsultingActivityBrowserClient ActivityClient
|
@inject IConsultingActivityBrowserClient ActivityClient
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/contracts"
|
@page "/admin/contracts"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@using TaxBaik.Web.Services.AdminClients
|
@using TaxBaik.Web.Services.AdminClients
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Shared
|
@using TaxBaik.WasmClient.Components.Admin.Shared
|
||||||
@inject IContractBrowserClient ContractClient
|
@inject IContractBrowserClient ContractClient
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
{
|
{
|
||||||
<MudText Typo="Typo.body2" Class="mt-2">
|
<MudText Typo="Typo.body2" Class="mt-2">
|
||||||
월 정기수익:
|
월 정기수익:
|
||||||
<MudChip Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled">₩@mrr.ToString("N0")</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled">₩@mrr.ToString("N0")</MudChip>
|
||||||
</MudText>
|
</MudText>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -224,7 +224,7 @@ else
|
|||||||
{
|
{
|
||||||
if (form != null)
|
if (form != null)
|
||||||
{
|
{
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!form.IsValid)
|
if (!form.IsValid)
|
||||||
{
|
{
|
||||||
Snackbar.Add("필수 항목을 입력해주세요.", Severity.Warning);
|
Snackbar.Add("필수 항목을 입력해주세요.", Severity.Warning);
|
||||||
|
|||||||
@@ -1,213 +1,14 @@
|
|||||||
@page "/admin/dashboard"
|
@page "/admin/dashboard"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
|
||||||
@using TaxBaik.Web.Services
|
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Shared
|
|
||||||
@inject IAdminDashboardClient DashboardClient
|
|
||||||
@inject NavigationManager Nav
|
|
||||||
|
|
||||||
<PageTitle>대시보드</PageTitle>
|
<PageTitle>대시보드</PageTitle>
|
||||||
|
|
||||||
<section class="admin-page-hero">
|
<section style="padding: 24px;">
|
||||||
<div>
|
<h1 style="margin: 0 0 12px 0; font-size: 1.8rem;">대시보드</h1>
|
||||||
<MudText Typo="Typo.caption" Class="admin-eyebrow">Overview</MudText>
|
<p style="margin: 0 0 12px 0;">관리자 SPA 부팅 검증용 최소 화면입니다.</p>
|
||||||
<MudText Typo="Typo.h4" Class="admin-page-title">대시보드</MudText>
|
<ul>
|
||||||
<MudText Typo="Typo.body2" Class="admin-page-subtitle">문의 흐름과 콘텐츠 상태를 한 화면에서 확인합니다.</MudText>
|
<li>WASM 부팅 성공 여부</li>
|
||||||
</div>
|
<li>라우팅 성공 여부</li>
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add" Href="/taxbaik/admin/blog/create">
|
<li>JS interop 예외 여부</li>
|
||||||
새 포스트 작성
|
</ul>
|
||||||
</MudButton>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@if (!string.IsNullOrEmpty(errorMessage))
|
|
||||||
{
|
|
||||||
<MudAlert Severity="Severity.Error" Class="mb-4">@errorMessage</MudAlert>
|
|
||||||
}
|
|
||||||
|
|
||||||
<AdminDataPanel Loading="@isLoading" SkeletonContent="@DashboardSkeleton">
|
|
||||||
<div class="admin-metric-grid">
|
|
||||||
<AdminMetricCard Label="이번달 문의" Value="@summary.ThisMonthInquiries" Caption="월간 상담 유입 (클릭 시 이동)" Accent="accent-blue" Icon="💬" ValueColor="var(--primary-dark)" IconColor="var(--primary-color)" OnClick="@GoInquiries" />
|
|
||||||
<AdminMetricCard Label="신규 문의" Value="@summary.NewInquiries" Caption="처리 대기 (클릭 시 이동)" Accent="accent-amber" Icon="⚠️" ValueColor="var(--tertiary-dark)" IconColor="var(--tertiary-color)" OnClick="@GoNewInquiries" />
|
|
||||||
<AdminMetricCard Label="전체 포스트" Value="@summary.TotalPosts" Caption="콘텐츠 자산 (클릭 시 이동)" Accent="accent-slate" Icon="📄" ValueColor="#455a64" IconColor="#607d8b" OnClick="@GoBlog" />
|
|
||||||
<AdminMetricCard Label="발행된 포스트" Value="@summary.PublishedPosts" Caption="검색 노출 대상 (클릭 시 이동)" Accent="accent-green" Icon="🌐" ValueColor="var(--secondary-dark)" IconColor="var(--secondary-color)" OnClick="@GoBlog" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (upcomingFilings.Count > 0)
|
|
||||||
{
|
|
||||||
<MudPaper Class="admin-surface mt-4" Elevation="0">
|
|
||||||
<div class="admin-section-header">
|
|
||||||
<div>
|
|
||||||
<MudText Typo="Typo.h6">이번 달 마감 임박 신고</MudText>
|
|
||||||
<MudText Typo="Typo.body2">30일 이내 신고 예정 건 (고객명 클릭 시 상세 카드로 연결)</MudText>
|
|
||||||
</div>
|
|
||||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" Href="/taxbaik/admin/tax-filings">전체 일정 보기</MudButton>
|
|
||||||
</div>
|
|
||||||
<MudSimpleTable Striped="true" Dense="true" Class="admin-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>고객</th>
|
|
||||||
<th>신고 유형</th>
|
|
||||||
<th>기한</th>
|
|
||||||
<th>D-day</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var f in upcomingFilings)
|
|
||||||
{
|
|
||||||
var dday = BusinessDayCalculator.GetDday(DateOnly.FromDateTime(f.DueDate));
|
|
||||||
var effectiveDueDate = BusinessDayCalculator.GetEffectiveDueDate(DateOnly.FromDateTime(f.DueDate));
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<MudLink Href="@($"/taxbaik/admin/clients/{f.ClientId}")" Underline="Underline.Hover" Color="Color.Primary" Class="font-weight-bold">
|
|
||||||
@f.ClientName
|
|
||||||
</MudLink>
|
|
||||||
</td>
|
|
||||||
<td>@f.FilingType</td>
|
|
||||||
<td>@effectiveDueDate.ToDateTime(TimeOnly.MinValue).ToString("yyyy-MM-dd")</td>
|
|
||||||
<td>
|
|
||||||
@if (dday < 0)
|
|
||||||
{
|
|
||||||
<MudChip T="string" Size="Size.Small" Color="Color.Dark">기한 초과 (@(-dday)일)</MudChip>
|
|
||||||
}
|
|
||||||
else if (dday <= 7)
|
|
||||||
{
|
|
||||||
<MudChip T="string" Size="Size.Small" Color="Color.Error">D-@dday</MudChip>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<span>D-@dday</span>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</MudSimpleTable>
|
|
||||||
</MudPaper>
|
|
||||||
}
|
|
||||||
|
|
||||||
<MudPaper Class="admin-surface mt-4" Elevation="0">
|
|
||||||
<div class="admin-section-header">
|
|
||||||
<div>
|
|
||||||
<MudText Typo="Typo.h6">최근 문의</MudText>
|
|
||||||
<MudText Typo="Typo.body2">최근 유입된 상담 요청을 빠르게 확인합니다. (이름 클릭 시 상세 관리 화면으로 연계)</MudText>
|
|
||||||
</div>
|
|
||||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" Href="/taxbaik/admin/inquiries">문의 전체 보기</MudButton>
|
|
||||||
</div>
|
|
||||||
<MudSimpleTable Striped="true" Dense="true" Class="admin-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>이름</th>
|
|
||||||
<th>전화</th>
|
|
||||||
<th>분야</th>
|
|
||||||
<th>상태</th>
|
|
||||||
<th>날짜</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var inquiry in summary.RecentInquiries)
|
|
||||||
{
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<MudLink Href="@($"/taxbaik/admin/inquiries?id={inquiry.Id}")" Underline="Underline.Hover" Color="Color.Primary" Class="font-weight-bold">
|
|
||||||
@inquiry.Name
|
|
||||||
</MudLink>
|
|
||||||
</td>
|
|
||||||
<td>@inquiry.Phone</td>
|
|
||||||
<td>@inquiry.ServiceType</td>
|
|
||||||
<td>
|
|
||||||
<MudChip T="string" Size="Size.Small" Color="@StatusColor(inquiry.Status)">
|
|
||||||
@GetStatusLabel(inquiry.Status)
|
|
||||||
</MudChip>
|
|
||||||
</td>
|
|
||||||
<td>@inquiry.CreatedAt.ToString("yyyy-MM-dd")</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</MudSimpleTable>
|
|
||||||
</MudPaper>
|
|
||||||
</AdminDataPanel>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
[CascadingParameter]
|
|
||||||
private Task<AuthenticationState>? AuthStateTask { get; set; }
|
|
||||||
|
|
||||||
private AdminDashboardSummary summary = new(0, 0, 0, 0, []);
|
|
||||||
private List<Domain.Entities.TaxFiling> upcomingFilings = [];
|
|
||||||
private string? errorMessage;
|
|
||||||
private bool isLoading = true;
|
|
||||||
|
|
||||||
private RenderFragment DashboardSkeleton => builder =>
|
|
||||||
{
|
|
||||||
builder.OpenComponent<AdminSkeletonRows>(0);
|
|
||||||
builder.AddAttribute(1, "Rows", 6);
|
|
||||||
builder.AddAttribute(2, "Columns", 4);
|
|
||||||
builder.CloseComponent();
|
|
||||||
};
|
|
||||||
|
|
||||||
private void GoInquiries()
|
|
||||||
{
|
|
||||||
Nav.NavigateTo("/taxbaik/admin/inquiries");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GoNewInquiries()
|
|
||||||
{
|
|
||||||
Nav.NavigateTo("/taxbaik/admin/inquiries?status=new");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GoBlog()
|
|
||||||
{
|
|
||||||
Nav.NavigateTo("/taxbaik/admin/blog");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
if (AuthStateTask != null)
|
|
||||||
{
|
|
||||||
var authState = await AuthStateTask;
|
|
||||||
if (authState.User.Identity?.IsAuthenticated == true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// AuthorizeRouteView already gates this page, so this branch is
|
|
||||||
// only a transient auth-state resolution timing gap - but without
|
|
||||||
// resetting isLoading here, AdminDataPanel would spin forever.
|
|
||||||
isLoading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
isLoading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetStatusLabel(string status) => InquiryStatusMapper.Labels.GetValueOrDefault(status, status);
|
|
||||||
|
|
||||||
private static Color StatusColor(string status) => status switch
|
|
||||||
{
|
|
||||||
"new" => Color.Warning,
|
|
||||||
"consulting" => Color.Info,
|
|
||||||
"contracted" => Color.Success,
|
|
||||||
"rejected" => Color.Error,
|
|
||||||
"closed" => Color.Dark,
|
|
||||||
_ => Color.Default
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@page "/admin/faqs/create"
|
@page "/admin/faqs/create"
|
||||||
@page "/admin/faqs/{Id:int}/edit"
|
@page "/admin/faqs/{Id:int}/edit"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@inject IFaqBrowserClient FaqClient
|
@inject IFaqBrowserClient FaqClient
|
||||||
@@ -27,14 +27,14 @@
|
|||||||
Label="질문 *" Required="true"
|
Label="질문 *" Required="true"
|
||||||
RequiredError="질문을 입력하세요."
|
RequiredError="질문을 입력하세요."
|
||||||
Counter="300" MaxLength="300"
|
Counter="300" MaxLength="300"
|
||||||
Lines="2" AutoGrow="true"
|
Lines="2"
|
||||||
Placeholder="예: 기장료가 얼마인지 미리 알 수 있나요?" />
|
Placeholder="예: 기장료가 얼마인지 미리 알 수 있나요?" />
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudTextField @bind-Value="model.Answer"
|
<MudTextField @bind-Value="model.Answer"
|
||||||
Label="답변 *" Required="true"
|
Label="답변 *" Required="true"
|
||||||
RequiredError="답변을 입력하세요."
|
RequiredError="답변을 입력하세요."
|
||||||
Lines="5" AutoGrow="true"
|
Lines="5"
|
||||||
Placeholder="방문자에게 보여질 답변을 입력하세요." />
|
Placeholder="방문자에게 보여질 답변을 입력하세요." />
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12" md="6">
|
<MudItem xs="12" md="6">
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
|
|
||||||
private async Task SaveAsync()
|
private async Task SaveAsync()
|
||||||
{
|
{
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!isValid) return;
|
if (!isValid) return;
|
||||||
|
|
||||||
isSaving = true;
|
isSaving = true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/faqs"
|
@page "/admin/faqs"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@using TaxBaik.Domain.Entities
|
@using TaxBaik.Domain.Entities
|
||||||
@@ -58,8 +58,8 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="d-flex align-center justify-start gap-1">
|
<div class="d-flex align-center justify-start gap-1">
|
||||||
<MudText Typo="Typo.body2" Class="mr-2">@item.SortOrder</MudText>
|
<MudText Typo="Typo.body2" Class="mr-2">@item.SortOrder</MudText>
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.ArrowDropUp" Size="Size.Small" OnClick="@(() => MoveUpAsync(item))" Style="padding:2px;" Dense="true" />
|
<MudIconButton Icon="@Icons.Material.Filled.ArrowDropUp" Size="Size.Small" OnClick="@(() => MoveUpAsync(item))" Style="padding:2px;" />
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.ArrowDropDown" Size="Size.Small" OnClick="@(() => MoveDownAsync(item))" Style="padding:2px;" Dense="true" />
|
<MudIconButton Icon="@Icons.Material.Filled.ArrowDropDown" Size="Size.Small" OnClick="@(() => MoveDownAsync(item))" Style="padding:2px;" />
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -70,17 +70,17 @@
|
|||||||
<td>
|
<td>
|
||||||
@if (!string.IsNullOrEmpty(item.Category))
|
@if (!string.IsNullOrEmpty(item.Category))
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Default">@item.Category</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Default">@item.Category</MudChip>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if (item.IsActive)
|
@if (item.IsActive)
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Success">노출 중</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Success">노출 중</MudChip>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudChip Size="Size.Small" Color="Color.Default">비활성</MudChip>
|
<MudChip T="string" Size="Size.Small" Color="Color.Default">비활성</MudChip>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/inquiries/create"
|
@page "/admin/inquiries/create"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.DTOs
|
@using TaxBaik.Application.DTOs
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Forms
|
@using TaxBaik.WasmClient.Components.Admin.Forms
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/inquiries/{InquiryId:int}"
|
@page "/admin/inquiries/{InquiryId:int}"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.Services
|
@using TaxBaik.Application.Services
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/inquiries/{id:int}/edit"
|
@page "/admin/inquiries/{id:int}/edit"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.DTOs
|
@using TaxBaik.Application.DTOs
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Forms
|
@using TaxBaik.WasmClient.Components.Admin.Forms
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/inquiries"
|
@page "/admin/inquiries"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.Services
|
@using TaxBaik.Application.Services
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/logout"
|
@page "/admin/logout"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@inject CustomAuthenticationStateProvider AuthStateProvider
|
@inject CustomAuthenticationStateProvider AuthStateProvider
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/revenue-trackings"
|
@page "/admin/revenue-trackings"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@using TaxBaik.Web.Services.AdminClients
|
@using TaxBaik.Web.Services.AdminClients
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Shared
|
@using TaxBaik.WasmClient.Components.Admin.Shared
|
||||||
@inject IRevenueTrackingBrowserClient RevenueClient
|
@inject IRevenueTrackingBrowserClient RevenueClient
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/season-simulator"
|
@page "/admin/season-simulator"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Application.Seasonal
|
@using TaxBaik.Application.Seasonal
|
||||||
@using TaxBaik.Application.Services
|
@using TaxBaik.Application.Services
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/settings"
|
@page "/admin/settings"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using System.Collections.Generic
|
@using System.Collections.Generic
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/tax-filing-schedules"
|
@page "/admin/tax-filing-schedules"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@using TaxBaik.Web.Services.AdminClients
|
@using TaxBaik.Web.Services.AdminClients
|
||||||
@using TaxBaik.Domain.Entities
|
@using TaxBaik.Domain.Entities
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Shared
|
@using TaxBaik.WasmClient.Components.Admin.Shared
|
||||||
@@ -227,7 +227,7 @@ else
|
|||||||
{
|
{
|
||||||
if (form != null)
|
if (form != null)
|
||||||
{
|
{
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!form.IsValid)
|
if (!form.IsValid)
|
||||||
{
|
{
|
||||||
Snackbar.Add("필수 항목을 입력해주세요.", Severity.Warning);
|
Snackbar.Add("필수 항목을 입력해주세요.", Severity.Warning);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/tax-filings"
|
@page "/admin/tax-filings"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
@using TaxBaik.Web.Services
|
@using TaxBaik.Web.Services
|
||||||
@using TaxBaik.Domain.Entities
|
@using TaxBaik.Domain.Entities
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<Client>> SearchClients(string value)
|
private async Task<IEnumerable<Client>> SearchClients(string value, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@page "/admin/tax-profiles"
|
@page "/admin/tax-profiles"
|
||||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: true))
|
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||||
@using System.ComponentModel.DataAnnotations
|
@using System.ComponentModel.DataAnnotations
|
||||||
@using TaxBaik.Web.Services.AdminClients
|
@using TaxBaik.Web.Services.AdminClients
|
||||||
@using TaxBaik.WasmClient.Components.Admin.Shared
|
@using TaxBaik.WasmClient.Components.Admin.Shared
|
||||||
@@ -202,7 +202,7 @@ else
|
|||||||
{
|
{
|
||||||
if (form != null)
|
if (form != null)
|
||||||
{
|
{
|
||||||
await form.Validate();
|
await form.ValidateAsync();
|
||||||
if (!form.IsValid)
|
if (!form.IsValid)
|
||||||
{
|
{
|
||||||
Snackbar.Add("고객을 선택하세요.", Severity.Warning);
|
Snackbar.Add("고객을 선택하세요.", Severity.Warning);
|
||||||
|
|||||||
@@ -3,11 +3,7 @@
|
|||||||
|
|
||||||
<Router AppAssembly="@typeof(TaxBaik.WasmClient.Components.Admin.Pages.AdminIndex).Assembly">
|
<Router AppAssembly="@typeof(TaxBaik.WasmClient.Components.Admin.Pages.AdminIndex).Assembly">
|
||||||
<Found Context="routeData">
|
<Found Context="routeData">
|
||||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(TaxBaik.WasmClient.Components.Admin.Layout.MainLayout)">
|
<RouteView RouteData="@routeData" DefaultLayout="@typeof(TaxBaik.WasmClient.Components.Admin.Layout.MainLayout)" />
|
||||||
<NotAuthorized>
|
|
||||||
<RedirectToLogin />
|
|
||||||
</NotAuthorized>
|
|
||||||
</AuthorizeRouteView>
|
|
||||||
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
||||||
</Found>
|
</Found>
|
||||||
<NotFound>
|
<NotFound>
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ public interface ILocalStorageService
|
|||||||
Task<string?> GetItemAsStringAsync(string key);
|
Task<string?> GetItemAsStringAsync(string key);
|
||||||
Task SetItemAsStringAsync(string key, string value);
|
Task SetItemAsStringAsync(string key, string value);
|
||||||
Task RemoveItemAsync(string key);
|
Task RemoveItemAsync(string key);
|
||||||
|
Task ClearAuthAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class LocalStorageService : ILocalStorageService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _jsRuntime.InvokeAsync<string>("localStorage.getItem", key);
|
return await _jsRuntime.InvokeAsync<string>("taxbaikAdminSession.getLocalStorageItem", key);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ public class LocalStorageService : ILocalStorageService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, value);
|
await _jsRuntime.InvokeVoidAsync("taxbaikAdminSession.setLocalStorageItem", key, value);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,20 @@ public class LocalStorageService : ILocalStorageService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", key);
|
await _jsRuntime.InvokeVoidAsync("taxbaikAdminSession.removeLocalStorageItem", key);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ClearAuthAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await RemoveItemAsync("accessToken");
|
||||||
|
await RemoveItemAsync("refreshToken");
|
||||||
|
await RemoveItemAsync("tokenExpiry");
|
||||||
|
await RemoveItemAsync("auth_token");
|
||||||
|
await RemoveItemAsync("admin-remembered-username");
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using TaxBaik.WasmClient.Components.Admin.Shared;
|
||||||
|
|
||||||
|
namespace MudBlazor;
|
||||||
|
|
||||||
|
public static class MudDialogServiceCompatExtensions
|
||||||
|
{
|
||||||
|
public static async Task<bool?> ShowMessageBox(
|
||||||
|
this IDialogService dialogService,
|
||||||
|
string title,
|
||||||
|
string message,
|
||||||
|
string yesText = "확인",
|
||||||
|
string? cancelText = null)
|
||||||
|
{
|
||||||
|
var parameters = new DialogParameters
|
||||||
|
{
|
||||||
|
{ "Title", title },
|
||||||
|
{ "Message", message }
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialog = await dialogService.ShowAsync<ConfirmDialog>(title, parameters);
|
||||||
|
var result = await dialog.Result;
|
||||||
|
return result?.Canceled == false ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
@inject IJSRuntime JS
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
<div class="admin-shell">
|
<div class="admin-shell">
|
||||||
@@ -89,14 +88,6 @@
|
|||||||
if (firstRender && !firstRenderCompleted)
|
if (firstRender && !firstRenderCompleted)
|
||||||
{
|
{
|
||||||
firstRenderCompleted = true;
|
firstRenderCompleted = true;
|
||||||
try
|
|
||||||
{
|
|
||||||
await JS.InvokeVoidAsync("taxbaikAdminSession.hideLoading");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Keep rendering even if the loading overlay helper is unavailable.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<MudTextField @bind-Value="EditModel.CodeValue" Label="값" Variant="Variant.Outlined" FullWidth="true" Required="true" Disabled="@(!IsCreateMode)" MaxLength="120" Class="mb-3" />
|
<MudTextField @bind-Value="EditModel.CodeValue" Label="값" Variant="Variant.Outlined" FullWidth="true" Required="true" Disabled="@(!IsCreateMode)" MaxLength="120" Class="mb-3" />
|
||||||
<MudTextField @bind-Value="EditModel.CodeName" Label="이름" Variant="Variant.Outlined" FullWidth="true" Required="true" MaxLength="200" Class="mb-3" />
|
<MudTextField @bind-Value="EditModel.CodeName" Label="이름" Variant="Variant.Outlined" FullWidth="true" Required="true" MaxLength="200" Class="mb-3" />
|
||||||
<MudNumericField T="int" @bind-Value="EditModel.SortOrder" Label="순서" Variant="Variant.Outlined" FullWidth="true" Class="mb-3" />
|
<MudNumericField T="int" @bind-Value="EditModel.SortOrder" Label="순서" Variant="Variant.Outlined" FullWidth="true" Class="mb-3" />
|
||||||
<MudSwitch @bind-Checked="EditModel.IsActive" Color="Color.Primary">활성</MudSwitch>
|
<MudSwitch T="bool" @bind-Value="EditModel.IsActive" Color="Color.Primary">활성</MudSwitch>
|
||||||
<div class="d-flex gap-2 mt-4">
|
<div class="d-flex gap-2 mt-4">
|
||||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="OnSaveRequested">저장</MudButton>
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="OnSaveRequested">저장</MudButton>
|
||||||
<MudButton Variant="Variant.Outlined" OnClick="OnResetRequested">초기화</MudButton>
|
<MudButton Variant="Variant.Outlined" OnClick="OnResetRequested">초기화</MudButton>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</MudDialog>
|
</MudDialog>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[CascadingParameter] MudDialogInstance MudDialog { get; set; } = null!;
|
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!;
|
||||||
[Parameter] public string Title { get; set; } = "";
|
[Parameter] public string Title { get; set; } = "";
|
||||||
[Parameter] public string Message { get; set; } = "";
|
[Parameter] public string Message { get; set; } = "";
|
||||||
|
|
||||||
|
|||||||
@@ -153,7 +153,6 @@ public class CustomAuthenticationStateProvider : AuthenticationStateProvider
|
|||||||
{
|
{
|
||||||
// TokenStore 초기화
|
// TokenStore 초기화
|
||||||
_tokenStore.Clear();
|
_tokenStore.Clear();
|
||||||
|
|
||||||
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ public interface ILocalStorageService
|
|||||||
Task<string?> GetItemAsStringAsync(string key);
|
Task<string?> GetItemAsStringAsync(string key);
|
||||||
Task SetItemAsStringAsync(string key, string value);
|
Task SetItemAsStringAsync(string key, string value);
|
||||||
Task RemoveItemAsync(string key);
|
Task RemoveItemAsync(string key);
|
||||||
|
Task ClearAuthAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class LocalStorageService : ILocalStorageService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _jsRuntime.InvokeAsync<string>("localStorage.getItem", key);
|
return await _jsRuntime.InvokeAsync<string>("taxbaikAdminSession.getLocalStorageItem", key);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ public class LocalStorageService : ILocalStorageService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, value);
|
await _jsRuntime.InvokeVoidAsync("taxbaikAdminSession.setLocalStorageItem", key, value);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,20 @@ public class LocalStorageService : ILocalStorageService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", key);
|
await _jsRuntime.InvokeVoidAsync("taxbaikAdminSession.removeLocalStorageItem", key);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ClearAuthAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await RemoveItemAsync("accessToken");
|
||||||
|
await RemoveItemAsync("refreshToken");
|
||||||
|
await RemoveItemAsync("tokenExpiry");
|
||||||
|
await RemoveItemAsync("auth_token");
|
||||||
|
await RemoveItemAsync("admin-remembered-username");
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
<StaticWebAssetBasePath>admin</StaticWebAssetBasePath>
|
<StaticWebAssetBasePath>admin</StaticWebAssetBasePath>
|
||||||
<StaticWebAssetFingerprintingEnabled>false</StaticWebAssetFingerprintingEnabled>
|
<StaticWebAssetFingerprintingEnabled>false</StaticWebAssetFingerprintingEnabled>
|
||||||
<StaticWebAssetsFingerprintContent>false</StaticWebAssetsFingerprintContent>
|
<StaticWebAssetsFingerprintContent>false</StaticWebAssetsFingerprintContent>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<DebugSymbols>false</DebugSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -21,7 +23,7 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.9" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.9" />
|
||||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.19.1" />
|
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.19.1" />
|
||||||
<PackageReference Include="MudBlazor" Version="6.10.0" />
|
<PackageReference Include="MudBlazor" Version="9.6.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.19.1" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.19.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FastEndpoints" Version="5.30.0" />
|
<PackageReference Include="FastEndpoints" Version="5.30.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.9" />
|
||||||
<PackageReference Include="MudBlazor" Version="6.10.0" />
|
<PackageReference Include="MudBlazor" Version="9.6.0" />
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="10.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="10.0.9" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.19.1" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.19.1" />
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ test.describe('admin authentication', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto(`${baseUrl}/admin/login`);
|
await page.goto(`${baseUrl}/admin/login`);
|
||||||
await expect(page.locator('input[placeholder="사용자명"]')).toBeVisible();
|
await expect(page.locator('#Username')).toBeVisible();
|
||||||
await expect(page.locator('input[placeholder="비밀번호"]')).toBeVisible();
|
await expect(page.locator('#Password')).toBeVisible();
|
||||||
|
|
||||||
// Wait for form to be fully ready
|
// Wait for form to be fully ready
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
const usernameInput = page.locator('input[placeholder="사용자명"]');
|
const usernameInput = page.locator('#Username');
|
||||||
const passwordInput = page.locator('input[placeholder="비밀번호"]');
|
const passwordInput = page.locator('#Password');
|
||||||
const loginButton = page.getByRole('button', { name: '로그인' });
|
const loginButton = page.getByRole('button', { name: '로그인' });
|
||||||
|
|
||||||
await usernameInput.fill(username);
|
await usernameInput.fill(username);
|
||||||
@@ -74,7 +74,8 @@ test.describe('admin authentication', () => {
|
|||||||
|
|
||||||
await expect(page).toHaveURL(/\/taxbaik\/admin\/dashboard$/, { timeout: 20_000 });
|
await expect(page).toHaveURL(/\/taxbaik\/admin\/dashboard$/, { timeout: 20_000 });
|
||||||
// WASM 부팅에 시간이 걸릴 수 있으므로 더 긴 타임아웃 사용
|
// WASM 부팅에 시간이 걸릴 수 있으므로 더 긴 타임아웃 사용
|
||||||
await expect(page.getByRole('heading', { name: '대시보드' }).first()).toBeVisible({ timeout: 60_000 });
|
await expect(page.locator('.admin-page-hero')).toBeVisible({ timeout: 60_000 });
|
||||||
|
await expect(page.locator('.admin-page-hero')).toContainText('대시보드');
|
||||||
await expect(page.getByRole('link', { name: /로그아웃/ })).toBeVisible({ timeout: 30_000 });
|
await expect(page.getByRole('link', { name: /로그아웃/ })).toBeVisible({ timeout: 30_000 });
|
||||||
expect(consoleErrors, 'browser console/page errors').toEqual([]);
|
expect(consoleErrors, 'browser console/page errors').toEqual([]);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user