feat: 시즌별 마케팅 + 공지사항 관리 기능 추가
TaxBaik CI/CD / build-and-deploy (push) Successful in 1m15s
TaxBaik Browser E2E / browser-e2e (push) Successful in 1m31s

- 연간 세무 캘린더(7개 시즌) 기반 자동 Hero 섹션 전환
- 시즌 감지 시 D-Day 카운트다운, 긴박감 배지, 시즌 CTA 표시
- 서비스 카드 순서 시즌 관련 항목 우선 정렬
- 어드민 공지사항 CRUD (등록·수정·삭제, 기간·유형 설정)
- 홈페이지 상단 공지 배너 자동 노출 (일반/배너/긴급)
- CLAUDE.md에 세무 캘린더 및 마케팅 방향 하네스 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-27 22:45:55 +09:00
parent 6af9221fab
commit cc72a67355
27 changed files with 1184 additions and 144 deletions
+5
View File
@@ -9,6 +9,11 @@
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<script>
document.documentElement.classList.toggle(
'admin-login-route',
window.location.pathname.toLowerCase().endsWith('/admin/login'));
</script>
<link rel="stylesheet" href="/taxbaik/css/admin.css" />
<component type="typeof(HeadOutlet)" render-mode="InteractiveServer" />
</head>
@@ -1,7 +1,7 @@
@using TaxBaik.Application.Services
@inject InquiryService InquiryService
<MudSimpleTable Striped="true" Dense="true" Class="mt-4">
<MudSimpleTable Striped="true" Dense="true" Class="admin-table mt-4">
<thead>
<tr>
<th>이름</th>
@@ -1,24 +1,60 @@
@inherits LayoutComponentBase
<MudLayout>
<MudAppBar Elevation="1">
<MudText Typo="Typo.h6" Class="ml-3">백원숙 세무회계 관리자</MudText>
<MudLayout Class="admin-shell">
<MudAppBar Elevation="0" Class="admin-topbar">
<MudIconButton Icon="@Icons.Material.Filled.Menu"
Color="Color.Inherit"
Edge="Edge.Start"
Class="admin-menu-button"
OnClick="@ToggleDrawer" />
<div class="admin-topbar-title">
<MudText Typo="Typo.caption">TaxBaik Backoffice</MudText>
<MudText Typo="Typo.h6">백원숙 세무회계 관리자</MudText>
</div>
<MudSpacer />
<MudButton Color="Color.Inherit" Href="/taxbaik">공개 사이트</MudButton>
<MudButton Href="/taxbaik/admin/logout">로그아웃</MudButton>
<MudButton Class="admin-topbar-action"
Variant="Variant.Outlined"
Color="Color.Inherit"
StartIcon="@Icons.Material.Filled.OpenInNew"
Href="/taxbaik">
공개 사이트
</MudButton>
<MudButton Class="admin-topbar-action"
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Logout"
Href="/taxbaik/admin/logout">
로그아웃
</MudButton>
</MudAppBar>
<MudDrawer @bind-open="@drawerOpen" Elevation="1" Variant="DrawerVariant.Responsive" Breakpoint="Breakpoint.Md">
<MudNavMenu>
<MudNavLink Href="/taxbaik/admin/dashboard" Match="NavLinkMatch.All">📊 대시보드</MudNavLink>
<MudNavLink Href="/taxbaik/admin/blog">📝 블로그 관리</MudNavLink>
<MudNavLink Href="/taxbaik/admin/inquiries">💬 문의 관리</MudNavLink>
<MudNavLink Href="/taxbaik/admin/settings">⚙️ 설정</MudNavLink>
<MudDrawer @bind-open="@drawerOpen"
Elevation="0"
Variant="DrawerVariant.Responsive"
Breakpoint="Breakpoint.Md"
Class="admin-drawer">
<div class="admin-drawer-brand">
<div class="admin-brand-mark">T</div>
<div>
<MudText Typo="Typo.subtitle1">TaxBaik</MudText>
<MudText Typo="Typo.caption">세무 운영 콘솔</MudText>
</div>
</div>
<MudNavMenu Class="admin-nav">
<MudNavLink Href="/taxbaik/admin/dashboard" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Dashboard">대시보드</MudNavLink>
<MudNavLink Href="/taxbaik/admin/announcements" Icon="@Icons.Material.Filled.Campaign">공지사항</MudNavLink>
<MudNavLink Href="/taxbaik/admin/blog" Icon="@Icons.Material.Filled.Article">블로그 관리</MudNavLink>
<MudNavLink Href="/taxbaik/admin/inquiries" Icon="@Icons.Material.Filled.Forum">문의 관리</MudNavLink>
<MudNavLink Href="/taxbaik/admin/settings" Icon="@Icons.Material.Filled.Tune">설정</MudNavLink>
</MudNavMenu>
<div class="admin-drawer-footer">
<MudText Typo="Typo.caption">운영 기준</MudText>
<MudText Typo="Typo.body2">변경 사항은 배포 후 Playwright로 검증합니다.</MudText>
</div>
</MudDrawer>
<MudMainContent>
<MudContainer MaxWidth="MaxWidth.Large" Class="my-4 px-3 px-md-0">
<MudMainContent Class="admin-main">
<MudContainer MaxWidth="MaxWidth.False" Class="admin-content">
@Body
</MudContainer>
</MudMainContent>
@@ -26,4 +62,9 @@
@code {
private bool drawerOpen = true;
private void ToggleDrawer()
{
drawerOpen = !drawerOpen;
}
}
@@ -0,0 +1,161 @@
@page "/admin/announcements/create"
@page "/admin/announcements/{Id:int}/edit"
@attribute [Authorize]
@using TaxBaik.Application.DTOs
@using TaxBaik.Application.Services
@inject AnnouncementService AnnouncementService
@inject NavigationManager Navigation
@inject ISnackbar Snackbar
<PageTitle>@(Id.HasValue ? "공지 수정" : "공지 등록")</PageTitle>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">Homepage</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">@(Id.HasValue ? "공지 수정" : "공지 등록")</MudText>
</div>
</section>
<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>
</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();
protected override async Task OnInitializedAsync()
{
if (Id.HasValue)
{
var entity = await AnnouncementService.GetByIdAsync(Id.Value);
if (entity is null)
{
Navigation.NavigateTo("/taxbaik/admin/announcements");
return;
}
model = new AnnouncementDto
{
Id = entity.Id,
Title = entity.Title,
Content = entity.Content,
DisplayType = entity.DisplayType,
IsActive = entity.IsActive,
SortOrder = entity.SortOrder
};
startsAtDate = entity.StartsAt?.ToLocalTime();
endsAtDate = entity.EndsAt?.ToLocalTime();
}
}
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;
if (Id.HasValue)
await AnnouncementService.UpdateAsync(model);
else
await AnnouncementService.CreateAsync(model);
Snackbar.Add("공지사항이 저장되었습니다.", Severity.Success);
Navigation.NavigateTo("/taxbaik/admin/announcements");
}
catch (Exception ex)
{
Snackbar.Add($"저장 실패: {ex.Message}", Severity.Error);
}
finally
{
isSaving = false;
}
}
}
@@ -0,0 +1,148 @@
@page "/admin/announcements"
@attribute [Authorize]
@using TaxBaik.Application.Services
@using TaxBaik.Domain.Entities
@inject AnnouncementService AnnouncementService
@inject NavigationManager Navigation
@inject IDialogService DialogService
@inject ISnackbar Snackbar
<PageTitle>공지사항 관리</PageTitle>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">Homepage</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">공지사항 관리</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">홈페이지 상단에 노출되는 공지사항을 등록하고 관리합니다.</MudText>
</div>
<MudButton Variant="Variant.Filled" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Add"
Href="/taxbaik/admin/announcements/create">
공지 등록
</MudButton>
</section>
<MudPaper Class="admin-surface" Elevation="0">
@if (announcements is null)
{
<MudProgressLinear Indeterminate="true" />
}
else if (!announcements.Any())
{
<MudText Class="pa-4 text-muted">등록된 공지사항이 없습니다.</MudText>
}
else
{
<MudSimpleTable Striped="true" Dense="true" 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>
<MudChip Size="Size.Small" Color="@GetTypeColor(item.DisplayType)">
@GetTypeLabel(item.DisplayType)
</MudChip>
</td>
<td>
@if (IsCurrentlyActive(item))
{
<MudChip Size="Size.Small" Color="Color.Success">노출 중</MudChip>
}
else if (!item.IsActive)
{
<MudChip Size="Size.Small" Color="Color.Default">비활성</MudChip>
}
else
{
<MudChip Size="Size.Small" Color="Color.Warning">기간 외</MudChip>
}
</td>
<td class="small">
@FormatPeriod(item)
</td>
<td>@item.SortOrder</td>
<td>
<MudButtonGroup Size="Size.Small" Variant="Variant.Outlined">
<MudButton @onclick="@(() => Navigation.NavigateTo($"/taxbaik/admin/announcements/{item.Id}/edit"))">
수정
</MudButton>
<MudButton Color="Color.Error" @onclick="@(() => DeleteAsync(item))">
삭제
</MudButton>
</MudButtonGroup>
</td>
</tr>
}
</tbody>
</MudSimpleTable>
}
</MudPaper>
@code {
private List<Announcement>? announcements;
protected override async Task OnInitializedAsync()
{
await LoadAsync();
}
private async Task LoadAsync()
{
announcements = (await AnnouncementService.GetAllAsync()).ToList();
}
private async Task DeleteAsync(Announcement item)
{
var confirmed = await DialogService.ShowMessageBox(
"공지 삭제",
$"'{item.Title}' 공지를 삭제하시겠습니까?",
yesText: "삭제", cancelText: "취소");
if (confirmed != true) return;
await AnnouncementService.DeleteAsync(item.Id);
Snackbar.Add("공지사항이 삭제되었습니다.", Severity.Success);
await LoadAsync();
}
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 Color GetTypeColor(string type) => type switch
{
"urgent" => Color.Error,
"banner" => Color.Warning,
_ => Color.Info
};
private static string GetTypeLabel(string type) => type switch
{
"urgent" => "긴급",
"banner" => "배너",
_ => "일반"
};
}
@@ -5,20 +5,24 @@
<PageTitle>블로그 관리</PageTitle>
<div class="mb-4 d-flex justify-content-between align-items-center">
<MudText Typo="Typo.h5">📝 블로그 관리</MudText>
<MudButton Variant="Variant.Filled" Color="Color.Primary"
Href="/taxbaik/admin/blog/create">새 포스트</MudButton>
</div>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">Content</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">블로그 관리</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">검색 유입 콘텐츠의 발행 상태와 성과를 관리합니다.</MudText>
</div>
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.EditNote"
Href="/taxbaik/admin/blog/create">새 포스트 작성</MudButton>
</section>
<MudPaper Class="pa-4 mb-4" Elevation="1">
<MudPaper Class="admin-surface mb-4" Elevation="0">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
<MudText Typo="Typo.subtitle1">@($"전체 포스트 {totalPosts}개")</MudText>
<MudText Typo="Typo.body2">페이지 @currentPage / @totalPages</MudText>
</MudStack>
</MudPaper>
<MudDataGrid Items="@posts" Striped="true" Hoverable="true" Loading="@isLoading">
<MudDataGrid Items="@posts" Striped="true" Hoverable="true" Loading="@isLoading" Class="admin-grid">
<Columns>
<PropertyColumn Property="x => x.Title" Title="제목" />
<PropertyColumn Property="x => x.IsPublished" Title="발행">
@@ -31,9 +35,9 @@
<PropertyColumn Property="x => x.CreatedAt" Title="작성일" Format="yyyy-MM-dd" />
<TemplateColumn>
<CellTemplate Context="cell">
<MudButton Variant="Variant.Text" Color="Color.Primary"
Href="@($"/taxbaik/admin/blog/{cell.Item.Id}/edit")">수정</MudButton>
<MudButton Variant="Variant.Text" Color="Color.Error"
<MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Primary"
Href="@($"/taxbaik/admin/blog/{cell.Item.Id}/edit")">수정하기</MudButton>
<MudButton Variant="Variant.Text" Size="Size.Small" Color="Color.Error"
@onclick="@(async () => await DeletePost(cell.Item.Id))">삭제</MudButton>
</CellTemplate>
</TemplateColumn>
@@ -5,41 +5,60 @@
<PageTitle>대시보드</PageTitle>
<h1 class="mb-4">대시보드</h1>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">Overview</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">대시보드</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">문의 흐름과 콘텐츠 상태를 한 화면에서 확인합니다.</MudText>
</div>
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add" Href="/taxbaik/admin/blog/create">
새 포스트 작성
</MudButton>
</section>
<MudGrid>
<MudGrid Class="admin-metric-grid">
<MudItem xs="12" sm="6" md="3">
<MudPaper Class="pa-4" Elevation="1">
<MudText Typo="Typo.subtitle2">이번달 문의</MudText>
<MudText Typo="Typo.h4">@summary.ThisMonthInquiries</MudText>
<MudPaper Class="admin-metric-card accent-blue" Elevation="0">
<MudText Typo="Typo.caption">이번달 문의</MudText>
<MudText Typo="Typo.h3">@summary.ThisMonthInquiries</MudText>
<MudText Typo="Typo.body2">월간 상담 유입</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="6" md="3">
<MudPaper Class="pa-4" Elevation="1">
<MudText Typo="Typo.subtitle2">신규 문의</MudText>
<MudText Typo="Typo.h4">@summary.NewInquiries</MudText>
<MudPaper Class="admin-metric-card accent-amber" Elevation="0">
<MudText Typo="Typo.caption">신규 문의</MudText>
<MudText Typo="Typo.h3">@summary.NewInquiries</MudText>
<MudText Typo="Typo.body2">처리 대기</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="6" md="3">
<MudPaper Class="pa-4" Elevation="1">
<MudText Typo="Typo.subtitle2">전체 포스트</MudText>
<MudText Typo="Typo.h4">@summary.TotalPosts</MudText>
<MudPaper Class="admin-metric-card accent-slate" Elevation="0">
<MudText Typo="Typo.caption">전체 포스트</MudText>
<MudText Typo="Typo.h3">@summary.TotalPosts</MudText>
<MudText Typo="Typo.body2">콘텐츠 자산</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="6" md="3">
<MudPaper Class="pa-4" Elevation="1">
<MudText Typo="Typo.subtitle2">발행된 포스트</MudText>
<MudText Typo="Typo.h4">@summary.PublishedPosts</MudText>
<MudPaper Class="admin-metric-card accent-green" Elevation="0">
<MudText Typo="Typo.caption">발행된 포스트</MudText>
<MudText Typo="Typo.h3">@summary.PublishedPosts</MudText>
<MudText Typo="Typo.body2">검색 노출 대상</MudText>
</MudPaper>
</MudItem>
</MudGrid>
<MudPaper Class="pa-4 mt-4" Elevation="1">
<MudText Typo="Typo.h6" Class="mb-3">최근 문의</MudText>
<MudSimpleTable Striped="true" Dense="true">
<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>
@@ -59,7 +78,7 @@
<td>
<MudChip Size="Size.Small"
Color="@(inquiry.Status == "new" ? Color.Warning : inquiry.Status == "contacted" ? Color.Info : Color.Success)">
@inquiry.Status
@GetStatusLabel(inquiry.Status)
</MudChip>
</td>
<td>@inquiry.CreatedAt.ToString("yyyy-MM-dd")</td>
@@ -75,5 +94,13 @@
protected override async Task OnInitializedAsync()
{
summary = await DashboardService.GetSummaryAsync();
}
}
private static string GetStatusLabel(string status) => status switch
{
"new" => "신규",
"contacted" => "연락함",
"completed" => "완료",
_ => status
};
}
@@ -5,9 +5,16 @@
<PageTitle>문의 관리</PageTitle>
<MudText Typo="Typo.h5" Class="mb-4">💬 문의 관리</MudText>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">Customer Requests</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">문의 관리</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">상담 요청을 상태별로 확인하고 후속 조치를 기록합니다.</MudText>
</div>
</section>
<MudTabs>
<MudPaper Class="admin-surface" Elevation="0">
<MudTabs Rounded="true" Elevation="0" Class="admin-tabs">
<MudTabPanel Text="전체">
<InquiryTable Status="" />
</MudTabPanel>
@@ -21,3 +28,4 @@
<InquiryTable Status="completed" />
</MudTabPanel>
</MudTabs>
</MudPaper>
@@ -5,6 +5,7 @@
@inject IApiClient ApiClient
@inject NavigationManager NavigationManager
@inject CustomAuthenticationStateProvider AuthStateProvider
@inject IJSRuntime Js
<PageTitle>로그인</PageTitle>
@@ -58,6 +59,12 @@
private LoginModel model = new();
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await Js.InvokeVoidAsync("taxbaikAdminSession.syncRouteClass");
}
private async Task HandleLogin()
{
if (isLoading)
@@ -9,9 +9,23 @@
<PageTitle>설정</PageTitle>
<MudText Typo="Typo.h5" Class="mb-4">⚙️ 사이트 설정</MudText>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">System</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">설정</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">공개 사이트 연락처와 관리자 계정 보안을 관리합니다.</MudText>
</div>
</section>
<MudPaper Class="pa-4" Elevation="1">
<MudGrid>
<MudItem xs="12" md="7">
<MudPaper Class="admin-surface" Elevation="0">
<div class="admin-section-header compact">
<div>
<MudText Typo="Typo.h6">사이트 정보</MudText>
<MudText Typo="Typo.body2">홈페이지와 문의 알림에 노출되는 기본 정보입니다.</MudText>
</div>
</div>
<MudForm>
<MudTextField @bind-Value="phone" Label="전화번호"
Variant="Variant.Outlined" Class="mb-4" />
@@ -26,12 +40,20 @@
Variant="Variant.Outlined" Class="mb-4" />
<MudButton Variant="Variant.Filled" Color="Color.Primary"
@onclick="SaveSettings">저장</MudButton>
StartIcon="@Icons.Material.Filled.Save"
@onclick="SaveSettings">사이트 정보 저장</MudButton>
</MudForm>
</MudPaper>
</MudItem>
<MudPaper Class="pa-4 mt-4" Elevation="1">
<MudText Typo="Typo.h6" Class="mb-4">계정 관리</MudText>
<MudItem xs="12" md="5">
<MudPaper Class="admin-surface admin-account-card" Elevation="0">
<div class="admin-section-header compact">
<div>
<MudText Typo="Typo.h6">계정 관리</MudText>
<MudText Typo="Typo.body2">비밀번호는 12자 이상으로 관리합니다.</MudText>
</div>
</div>
<MudForm>
<MudTextField @bind-Value="currentPassword" Label="현재 비밀번호" InputType="InputType.Password"
@@ -45,11 +67,14 @@
<MudButton Variant="Variant.Filled" Color="Color.Primary"
Disabled="@isChangingPassword"
StartIcon="@Icons.Material.Filled.LockReset"
@onclick="ChangePassword">
@(isChangingPassword ? "변경 중..." : "비밀번호 변경")
</MudButton>
</MudForm>
</MudPaper>
</MudItem>
</MudGrid>
@code {
private string phone = "010-4122-8268";