revert: rollback Fluent UI and Blazor homepage to last successful state (3be3794)

This commit is contained in:
2026-06-30 20:29:42 +09:00
parent 488b8d11b7
commit 54c179b1eb
69 changed files with 3996 additions and 2904 deletions
@@ -4,63 +4,95 @@
@using TaxBaik.Domain.Entities
@inject IFaqBrowserClient FaqClient
@inject NavigationManager Navigation
@inject IJSRuntime JS
@inject IDialogService DialogService
@inject ISnackbar Snackbar
<PageTitle>FAQ 관리</PageTitle>
<section class="admin-page-hero">
<div>
<div class="admin-eyebrow">홈페이지</div>
<h1 class="admin-page-title">FAQ 관리</h1>
<p class="admin-page-subtitle">홈페이지 자주 묻는 질문을 등록하고 순서를 관리합니다.</p>
<MudText Typo="Typo.caption" Class="admin-eyebrow">홈페이지</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">FAQ 관리</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">홈페이지 자주 묻는 질문을 등록하고 순서를 관리합니다.</MudText>
</div>
<a class="site-button primary" href="/taxbaik/admin/faqs/create">FAQ 등록</a>
<MudButton Variant="Variant.Filled" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Add"
Href="/taxbaik/admin/faqs/create">
FAQ 등록
</MudButton>
</section>
<div class="admin-surface">
<MudPaper Class="admin-surface" Elevation="0">
@if (faqs is null)
{
<Skeleton Count="5" CssClass="taxbaik-skeleton-grid" />
<MudProgressLinear Indeterminate="true" />
}
else if (!faqs.Any())
{
<div class="muted">등록된 FAQ가 없습니다.</div>
<div class="pa-6 text-center">
<MudIcon Icon="@Icons.Material.Filled.QuestionAnswer" Style="font-size:3rem; opacity:.3;" />
<MudText Class="mt-2 text-muted">등록된 FAQ가 없습니다.</MudText>
</div>
}
else
{
<div class="admin-table-wrap">
<table class="admin-table">
<thead>
<MudSimpleTable Striped="true" Dense="true" Class="admin-table">
<thead>
<tr>
<th style="width:60px;">순서</th>
<th>질문</th>
<th style="width:130px;">카테고리</th>
<th style="width:90px;">상태</th>
<th style="width:160px;"></th>
</tr>
</thead>
<tbody>
@foreach (var item in faqs)
{
<tr>
<th>순서</th>
<th>질문</th>
<th>카테고리</th>
<th>상태</th>
<th></th>
<td class="text-center">
<MudText Typo="Typo.body2">@item.SortOrder</MudText>
</td>
<td>
<MudText Typo="Typo.body2" Style="max-width:480px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">
@item.Question
</MudText>
</td>
<td>
@if (!string.IsNullOrEmpty(item.Category))
{
<MudChip Size="Size.Small" Color="Color.Default">@item.Category</MudChip>
}
</td>
<td>
@if (item.IsActive)
{
<MudChip Size="Size.Small" Color="Color.Success">노출 중</MudChip>
}
else
{
<MudChip Size="Size.Small" Color="Color.Default">비활성</MudChip>
}
</td>
<td>
<MudButtonGroup Size="Size.Small" Variant="Variant.Outlined">
<MudButton @onclick="@(() => Navigation.NavigateTo($"/taxbaik/admin/faqs/{item.Id}/edit"))">
수정
</MudButton>
<MudButton Color="Color.Error" @onclick="@(() => DeleteAsync(item))">
삭제
</MudButton>
</MudButtonGroup>
</td>
</tr>
</thead>
<tbody>
@foreach (var item in faqs)
{
<tr>
<td>@item.SortOrder</td>
<td>@item.Question</td>
<td>@(string.IsNullOrEmpty(item.Category) ? "" : item.Category)</td>
<td><span class="status-pill @(item.IsActive ? "success" : "default")">@(item.IsActive ? "노출 중" : "비활성")</span></td>
<td>
<div class="admin-actions">
<button type="button" class="admin-icon-button" @onclick="@(() => Navigation.NavigateTo($"/taxbaik/admin/faqs/{item.Id}/edit"))">✎</button>
<button type="button" class="admin-icon-button danger" @onclick="@(() => DeleteAsync(item))">✕</button>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="muted mt-2">총 @(faqs.Count)개 · 노출 중 @(faqs.Count(f => f.IsActive))개</div>
}
</tbody>
</MudSimpleTable>
<MudText Typo="Typo.caption" Class="pa-2 text-muted">
총 @(faqs.Count)개 · 노출 중 @(faqs.Count(f => f.IsActive))개
</MudText>
}
</div>
</MudPaper>
@code {
[CascadingParameter]
@@ -70,13 +102,16 @@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && AuthStateTask != null)
if (firstRender)
{
var authState = await AuthStateTask;
if (authState.User.Identity?.IsAuthenticated == true)
if (AuthStateTask != null)
{
await LoadAsync();
StateHasChanged();
var authState = await AuthStateTask;
if (authState.User.Identity?.IsAuthenticated == true)
{
await LoadAsync();
StateHasChanged();
}
}
}
}
@@ -89,32 +124,36 @@
}
catch (Exception ex)
{
await JS.InvokeVoidAsync("alert", $"오류: {ex.Message}");
Snackbar.Add($"오류: {ex.Message}", Severity.Error);
faqs = [];
}
}
private async Task DeleteAsync(Faq item)
{
var confirmed = await JS.InvokeAsync<bool>("confirm", $"'{item.Question}' 항목을 삭제하시겠습니까?");
if (!confirmed) return;
var confirmed = await DialogService.ShowMessageBox(
"FAQ 삭제",
$"'{item.Question}' 항목을 삭제하시겠습니까?",
yesText: "삭제", cancelText: "취소");
if (confirmed != true) return;
try
{
var success = await FaqClient.DeleteAsync(item.Id);
if (success)
{
await JS.InvokeVoidAsync("alert", "FAQ가 삭제되었습니다.");
Snackbar.Add("FAQ가 삭제되었습니다.", Severity.Success);
await LoadAsync();
}
else
{
await JS.InvokeVoidAsync("alert", "삭제 실패");
Snackbar.Add("삭제 실패", Severity.Error);
}
}
catch (Exception ex)
{
await JS.InvokeVoidAsync("alert", $"오류: {ex.Message}");
Snackbar.Add($"오류: {ex.Message}", Severity.Error);
}
}
}