Files
taxbaik/TaxBaik.Web.Client/Components/Admin/Pages/Blog/BlogEdit.razor
T
kjh2064 8202c3278b
TaxBaik CI/CD / build-and-deploy (push) Failing after 2m17s
refactor: complete WebAssembly migration - proper architecture
Phase 8: Complete WebAssembly 렌더 모드 전환 (정공법)

Migration Summary:
- ALL Admin components → TaxBaik.Web.Client
- Routes.razor, Pages/*, Layout/*, Shared/*, Forms/*
- App.razor → TaxBaik.WasmClient (호스트 컴포넌트)
- Shared utilities → TaxBaik.Application.Utils

Architecture:
 App.razor: TaxBaik.WasmClient (WebAssembly, 호스트)
 Routes + Pages: TaxBaik.WasmClient (WebAssembly)
 Layout + Shared + Forms: TaxBaik.WasmClient (WebAssembly)
 Services: TaxBaik.Web (API-First)

Key Changes:
- Namespaces: TaxBaik.Web.Components.Admin → TaxBaik.WasmClient.Components.Admin
- Shared utilities: TaxBaik.Application.Utils (single source of truth)
- Program.cs: MapRazorComponents<TaxBaik.WasmClient.Components.Admin.App>()
- _Imports.razor: Components/Admin 폴더에 재구성

Build Status:  0 errors, 0 warnings

Benefits:
- Stateless server (no Circuit memory)
- Client-side rendering (WebAssembly)
- Unlimited concurrent users (horizontal scaling)
- ERP-ready architecture

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-03 01:03:51 +09:00

155 lines
4.6 KiB
Plaintext

@page "/admin/blog/{id:int}/edit"
@attribute [Authorize]
@using TaxBaik.Application.DTOs
@using TaxBaik.WasmClient.Components.Admin.Pages.Blog
@inject IBlogBrowserClient BlogClient
@inject ICategoryBrowserClient CategoryClient
@inject NavigationManager Navigation
@inject ISnackbar Snackbar
@inject IDialogService DialogService
<PageTitle>포스트 수정</PageTitle>
<AdminCrudPageShell Title="포스트 수정"
Eyebrow="Content"
Subtitle="블로그 포스트를 수정합니다."
Loading="@isLoading"
SkeletonContent="@EditorSkeleton"
OnCancel="@GoBack">
@if (post == null)
{
<MudAlert Severity="Severity.Error" Class="mt-4">포스트를 찾을 수 없습니다.</MudAlert>
}
else
{
<MudPaper Class="pa-4 mt-4" Elevation="1">
<BlogForm Model="model" Categories="categories" SubmitText="저장" OnSubmit="SavePost" />
<div class="mt-4">
<MudButton Variant="Variant.Outlined" Color="Color.Error" @onclick="DeletePost">삭제</MudButton>
</div>
</MudPaper>
}
</AdminCrudPageShell>
@code {
[Parameter]
public int Id { get; set; }
private TaxBaik.Application.DTOs.BlogPostResponseDto? post;
private IReadOnlyList<Domain.Entities.Category> categories = [];
private BlogForm.BlogFormModel model = new();
private bool isLoading = true;
private RenderFragment EditorSkeleton => builder =>
{
builder.OpenComponent<AdminSkeletonRows>(0);
builder.AddAttribute(1, "Rows", 5);
builder.AddAttribute(2, "Columns", 3);
builder.CloseComponent();
};
protected override async Task OnInitializedAsync()
{
try
{
post = await BlogClient.GetByIdAsync(Id);
if (post != null)
{
categories = await CategoryClient.GetAllAsync();
MapPostToModel(post);
}
}
catch (Exception ex)
{
Snackbar.Add($"포스트 로드 실패: {ex.Message}", Severity.Error);
}
finally
{
isLoading = false;
}
}
private void MapPostToModel(TaxBaik.Application.DTOs.BlogPostResponseDto post)
{
model.Title = post.Title;
model.Content = post.Content;
model.CategoryId = post.CategoryId;
model.Tags = post.Tags;
model.SeoTitle = post.SeoTitle;
model.SeoDescription = post.SeoDescription;
model.IsPublished = post.IsPublished;
}
private void GoBack()
{
Navigation.NavigateTo("/taxbaik/admin/blog");
}
private async Task SavePost()
{
if (post == null)
return;
try
{
var result = await BlogClient.UpdateAsync(post.Id, new CreateBlogPostDto
{
Title = model.Title,
Content = model.Content,
CategoryId = model.CategoryId,
Tags = model.Tags,
SeoTitle = model.SeoTitle,
SeoDescription = model.SeoDescription,
IsPublished = model.IsPublished
});
if (result == null)
{
Snackbar.Add("저장 실패: 포스트를 저장하지 못했습니다.", Severity.Error);
return;
}
Snackbar.Add("포스트가 저장되었습니다.", Severity.Success);
Navigation.NavigateTo("/taxbaik/admin/blog");
}
catch (ValidationException ex)
{
Snackbar.Add(ex.Message, Severity.Error);
}
catch (Exception ex)
{
Snackbar.Add($"저장 실패: {ex.Message}", Severity.Error);
}
}
private async Task DeletePost()
{
if (post == null)
return;
var result = await DialogService.ShowMessageBox(
"포스트 삭제",
"정말 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.",
"삭제", "취소");
if (result != true)
return;
try
{
var deleted = await BlogClient.DeleteAsync(post.Id);
if (!deleted)
{
Snackbar.Add("삭제 실패: 포스트를 삭제하지 못했습니다.", Severity.Error);
return;
}
Snackbar.Add("포스트가 삭제되었습니다.", Severity.Success);
Navigation.NavigateTo("/taxbaik/admin/blog");
}
catch (Exception ex)
{
Snackbar.Add($"삭제 실패: {ex.Message}", Severity.Error);
}
}
}