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
@@ -5,47 +5,101 @@
@using TaxBaik.Web.Services
@inject IAnnouncementBrowserClient AnnouncementClient
@inject NavigationManager Navigation
@inject IJSRuntime JS
@inject ISnackbar Snackbar
<PageTitle>@(Id.HasValue ? "공지 수정" : "공지 등록")</PageTitle>
<section class="admin-page-hero">
<div>
<div class="admin-eyebrow">Homepage</div>
<h1 class="admin-page-title">@(Id.HasValue ? "공지 수정" : "공지 등록")</h1>
<MudText Typo="Typo.caption" Class="admin-eyebrow">Homepage</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">@(Id.HasValue ? "공지 수정" : "공지 등록")</MudText>
</div>
</section>
<div class="admin-surface" style="max-width:720px;">
<form class="admin-dialog-card" @onsubmit="SaveAsync" @onsubmit:preventDefault="true">
<label>제목 * <input class="admin-input" @bind="model.Title" /></label>
<label>상세 내용 (선택) <textarea class="admin-input" rows="3" @bind="model.Content"></textarea></label>
<label>유형
<select class="admin-input" @bind="model.DisplayType">
<option value="info">일반 (파란색)</option>
<option value="banner">배너 (주황색)</option>
<option value="urgent">긴급 (빨간색)</option>
</select>
</label>
<label>노출 순서 <input class="admin-input" type="number" @bind="model.SortOrder" /></label>
<label>게시 시작일 <input class="admin-input" type="text" placeholder="yyyy-MM-dd" @bind="StartsAtText" /></label>
<label>게시 종료일 <input class="admin-input" type="text" placeholder="yyyy-MM-dd" @bind="EndsAtText" /></label>
<label><input type="checkbox" @bind="model.IsActive" /> @(model.IsActive ? "활성화" : "비활성화")</label>
<div class="admin-dialog-actions">
<button type="submit" class="site-button primary" disabled="@isSaving">저장</button>
<button type="button" class="site-button secondary" @onclick='() => Navigation.NavigateTo("/taxbaik/admin/announcements")'>취소</button>
<MudPaper Class="admin-surface" Elevation="0">
<MudForm @ref="form">
<MudGrid>
<MudItem xs="12">
<MudTextField @bind-Value="model.Title"
Label="제목"
Variant="Variant.Outlined"
Required="true"
RequiredError="제목을 입력하세요."
HelperText="홈페이지 상단 공지 바에 표시되는 텍스트입니다." />
</MudItem>
<MudItem xs="12">
<MudTextField @bind-Value="model.Content"
Label="상세 내용 (선택)"
Variant="Variant.Outlined"
Lines="3"
HelperText="부가 설명이 있을 경우 입력합니다. 없으면 제목만 표시됩니다." />
</MudItem>
<MudItem xs="12" sm="6">
<MudSelect @bind-Value="model.DisplayType"
Label="유형"
Variant="Variant.Outlined">
<MudSelectItem Value="@("info")">일반 (파란색)</MudSelectItem>
<MudSelectItem Value="@("banner")">배너 (주황색) — 중요 이벤트</MudSelectItem>
<MudSelectItem Value="@("urgent")">긴급 (빨간색) — 마감 임박</MudSelectItem>
</MudSelect>
</MudItem>
<MudItem xs="12" sm="6">
<MudNumericField @bind-Value="model.SortOrder"
Label="노출 순서"
Variant="Variant.Outlined"
HelperText="숫자가 클수록 먼저 표시됩니다." />
</MudItem>
<MudItem xs="12" sm="6">
<MudDatePicker @bind-Date="startsAtDate"
Label="게시 시작일 (비우면 즉시)"
Variant="Variant.Outlined"
DateFormat="yyyy-MM-dd"
Clearable="true" />
</MudItem>
<MudItem xs="12" sm="6">
<MudDatePicker @bind-Date="endsAtDate"
Label="게시 종료일 (비우면 무기한)"
Variant="Variant.Outlined"
DateFormat="yyyy-MM-dd"
Clearable="true" />
</MudItem>
<MudItem xs="12">
<MudSwitch @bind-Checked="model.IsActive"
Label="@(model.IsActive ? "활성화 (홈페이지에 노출)" : "비활성화 (홈페이지 미노출)")"
Color="Color.Primary" />
</MudItem>
</MudGrid>
<div class="d-flex gap-2 mt-4">
<MudButton Variant="Variant.Filled" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Save"
Disabled="isSaving"
@onclick="SaveAsync">
@(isSaving ? "저장 중..." : "저장")
</MudButton>
<MudButton Variant="Variant.Outlined"
@onclick="@(() => Navigation.NavigateTo("/taxbaik/admin/announcements"))">
취소
</MudButton>
</div>
</form>
</div>
</MudForm>
</MudPaper>
@code {
[Parameter] public int? Id { get; set; }
private MudForm? form;
private bool isSaving;
private DateTime? startsAtDate;
private DateTime? endsAtDate;
private AnnouncementDto model = new();
private string StartsAtText { get => startsAtDate?.ToString("yyyy-MM-dd") ?? ""; set => startsAtDate = DateTime.TryParse(value, out var dt) ? dt : null; }
private string EndsAtText { get => endsAtDate?.ToString("yyyy-MM-dd") ?? ""; set => endsAtDate = DateTime.TryParse(value, out var dt) ? dt : null; }
protected override async Task OnInitializedAsync()
{
@@ -61,15 +115,15 @@
}
model = new AnnouncementDto
{
Id = entity.Id,
Title = entity.Title,
Content = entity.Content,
Id = entity.Id,
Title = entity.Title,
Content = entity.Content,
DisplayType = entity.DisplayType,
IsActive = entity.IsActive,
SortOrder = entity.SortOrder
IsActive = entity.IsActive,
SortOrder = entity.SortOrder
};
startsAtDate = entity.StartsAt?.ToLocalTime();
endsAtDate = entity.EndsAt?.ToLocalTime();
endsAtDate = entity.EndsAt?.ToLocalTime();
}
catch
{
@@ -80,18 +134,41 @@
private async Task SaveAsync()
{
if (form is null) return;
await form.Validate();
if (!form.IsValid) return;
isSaving = true;
try
{
model.StartsAt = startsAtDate.HasValue ? DateTime.SpecifyKind(startsAtDate.Value.Date, DateTimeKind.Local).ToUniversalTime() : null;
model.EndsAt = endsAtDate.HasValue ? DateTime.SpecifyKind(endsAtDate.Value.Date.AddDays(1).AddSeconds(-1), DateTimeKind.Local).ToUniversalTime() : null;
var result = Id.HasValue ? await AnnouncementClient.UpdateAsync(Id.Value, model) : await AnnouncementClient.CreateAsync(model);
await JS.InvokeVoidAsync("alert", result != null ? "공지사항이 저장되었습니다." : "저장 실패");
model.StartsAt = startsAtDate.HasValue
? DateTime.SpecifyKind(startsAtDate.Value.Date, DateTimeKind.Local).ToUniversalTime()
: null;
model.EndsAt = endsAtDate.HasValue
? DateTime.SpecifyKind(endsAtDate.Value.Date.AddDays(1).AddSeconds(-1), DateTimeKind.Local).ToUniversalTime()
: null;
if (Id.HasValue)
{
var result = await AnnouncementClient.UpdateAsync(Id.Value, model);
if (result != null)
Snackbar.Add("공지사항이 저장되었습니다.", Severity.Success);
else
Snackbar.Add("저장 실패", Severity.Error);
}
else
{
var result = await AnnouncementClient.CreateAsync(model);
if (result != null)
Snackbar.Add("공지사항이 저장되었습니다.", Severity.Success);
else
Snackbar.Add("저장 실패", Severity.Error);
}
Navigation.NavigateTo("/taxbaik/admin/announcements");
}
catch (Exception ex)
{
await JS.InvokeVoidAsync("alert", $"저장 실패: {ex.Message}");
Snackbar.Add($"저장 실패: {ex.Message}", Severity.Error);
}
finally
{