Files
taxbaik/TaxBaik.Web/Components/Admin/Pages/Announcements/AnnouncementList.razor
T
kjh2064 1b173376ee
TaxBaik CI/CD / build-and-deploy (push) Failing after 1m53s
refactor: admin ui를 fluent v5와 html 기반으로 전환
2026-06-29 22:37:40 +09:00

158 lines
5.2 KiB
Plaintext

@page "/admin/announcements"
@attribute [Authorize]
@using TaxBaik.Web.Services
@using TaxBaik.Domain.Entities
@inject IAnnouncementBrowserClient AnnouncementClient
@inject NavigationManager Navigation
@inject IJSRuntime JS
<PageTitle>공지사항 관리</PageTitle>
<section class="admin-page-hero">
<div>
<div class="admin-eyebrow">Homepage</div>
<h1 class="admin-page-title">공지사항 관리</h1>
<p class="admin-page-subtitle">홈페이지 상단에 노출되는 공지사항을 등록하고 관리합니다.</p>
</div>
<a class="site-button primary" href="/taxbaik/admin/announcements/create">공지 등록</a>
</section>
<div class="admin-surface">
@if (announcements is null)
{
<Skeleton Count="5" CssClass="taxbaik-skeleton-grid" />
}
else if (!announcements.Any())
{
<div class="muted">등록된 공지사항이 없습니다.</div>
}
else
{
<div class="admin-table-wrap">
<table class="admin-table">
<thead>
<tr>
<th>제목</th>
<th>유형</th>
<th>상태</th>
<th>게시 기간</th>
<th>순서</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in announcements)
{
<tr>
<td>@item.Title</td>
<td><span class="status-pill info">@GetTypeLabel(item.DisplayType)</span></td>
<td>
@if (IsCurrentlyActive(item))
{
<span class="status-pill success">노출 중</span>
}
else if (!item.IsActive)
{
<span class="status-pill default">비활성</span>
}
else
{
<span class="status-pill warning">기간 외</span>
}
</td>
<td class="small">@FormatPeriod(item)</td>
<td>@item.SortOrder</td>
<td>
<div class="admin-actions">
<button type="button" class="admin-icon-button" @onclick="@(() => Navigation.NavigateTo($"/taxbaik/admin/announcements/{item.Id}/edit"))">✎</button>
<button type="button" class="admin-icon-button danger" @onclick="@(() => DeleteAsync(item))">✕</button>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
@code {
[CascadingParameter]
private Task<AuthenticationState>? AuthStateTask { get; set; }
private List<Announcement>? announcements;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && AuthStateTask != null)
{
var authState = await AuthStateTask;
if (authState.User.Identity?.IsAuthenticated == true)
{
await LoadAsync();
StateHasChanged();
}
}
}
private async Task LoadAsync()
{
try
{
announcements = (await AnnouncementClient.GetAllAsync()).ToList();
}
catch (Exception ex)
{
await JS.InvokeVoidAsync("alert", $"오류: {ex.Message}");
announcements = [];
}
}
private async Task DeleteAsync(Announcement item)
{
var confirmed = await JS.InvokeAsync<bool>("confirm", $"'{item.Title}' 공지를 삭제하시겠습니까?");
if (!confirmed) return;
try
{
var success = await AnnouncementClient.DeleteAsync(item.Id);
if (success)
{
await JS.InvokeVoidAsync("alert", "공지사항이 삭제되었습니다.");
await LoadAsync();
}
else
{
await JS.InvokeVoidAsync("alert", "삭제 실패");
}
}
catch (Exception ex)
{
await JS.InvokeVoidAsync("alert", $"오류: {ex.Message}");
}
}
private static bool IsCurrentlyActive(Announcement a)
{
if (!a.IsActive) return false;
var now = DateTime.UtcNow;
if (a.StartsAt.HasValue && a.StartsAt > now) return false;
if (a.EndsAt.HasValue && a.EndsAt < now) return false;
return true;
}
private static string FormatPeriod(Announcement a)
{
var start = a.StartsAt?.ToLocalTime().ToString("MM/dd") ?? "즉시";
var end = a.EndsAt?.ToLocalTime().ToString("MM/dd") ?? "무기한";
return $"{start} ~ {end}";
}
private static string GetTypeLabel(string type) => type switch
{
"urgent" => "긴급",
"banner" => "배너",
_ => "일반"
};
}