Files
taxbaik/TaxBaik.Web/Components/Admin/Pages/SeasonSimulator.razor
T

212 lines
10 KiB
Plaintext

@page "/admin/season-simulator"
@attribute [Authorize]
@using TaxBaik.Application.Seasonal
@using TaxBaik.Application.Services
<PageTitle>시즌 시뮬레이터</PageTitle>
<section class="admin-page-hero">
<div>
<MudText Typo="Typo.caption" Class="admin-eyebrow">Season Preview</MudText>
<MudText Typo="Typo.h4" Class="admin-page-title">시즌 시뮬레이터</MudText>
<MudText Typo="Typo.body2" Class="admin-page-subtitle">날짜를 선택해 홈페이지 시즌 화면이 어떻게 보이는지 미리 확인합니다.</MudText>
</div>
</section>
<MudGrid>
<MudItem xs="12" md="4">
<MudPaper Class="pa-4" Elevation="1">
<MudText Typo="Typo.h6" Class="mb-3">시뮬레이션 날짜</MudText>
<MudDatePicker @bind-Date="simulationDate" Label="날짜 선택" DateFormat="yyyy-MM-dd" PickerVariant="PickerVariant.Static" />
<MudDivider Class="my-3" />
<MudText Typo="Typo.subtitle2" Class="mb-2">연간 세무 캘린더</MudText>
@foreach (var season in TaxSeasonCalendar.Seasons)
{
<MudButton Variant="Variant.Outlined" Size="Size.Small" FullWidth="true"
Class="mb-1" Color="Color.Primary"
OnClick="@(() => JumpToSeason(season))">
@season.StartMonth/@season.StartDay — @season.Name
</MudButton>
}
</MudPaper>
</MudItem>
<MudItem xs="12" md="8">
<MudPaper Class="pa-4" Elevation="1">
<MudText Typo="Typo.h6" Class="mb-1">
@(simulationDate?.ToString("yyyy년 MM월 dd일") ?? "날짜를 선택하세요") 홈페이지 미리보기
</MudText>
@if (activeSeason != null)
{
<MudChip T="string" Color="Color.Warning" Size="Size.Small" Class="mb-3">
@activeSeason.Name 시즌 활성
</MudChip>
<MudDivider Class="mb-4" />
<!-- Hero 섹션 미리보기 -->
<div style="background: linear-gradient(135deg, #1a365d 0%, #2a4365 100%); border-radius: 12px; padding: 2rem; color: white; margin-bottom: 1.5rem;">
@if (activeSeason.DaysUntilDeadline <= 7 && activeSeason.DaysUntilDeadline >= 0)
{
<div style="background: #f59e0b; color: #1a202c; display: inline-block; padding: 4px 12px; border-radius: 20px; font-size: 0.8rem; font-weight: 700; margin-bottom: 1rem;">
D-@activeSeason.DaysUntilDeadline 마감 임박
</div>
}
<div style="font-size: 1.8rem; font-weight: 800; white-space: pre-line; margin-bottom: 0.5rem; line-height: 1.3;">
@activeSeason.HeroHeadline
</div>
<div style="font-size: 0.95rem; color: rgba(255,255,255,0.8); margin-bottom: 1.5rem;">
@activeSeason.HeroSubtext
</div>
<div style="display: flex; gap: 0.75rem; flex-wrap: wrap;">
<div style="background: #e53e3e; color: white; padding: 10px 20px; border-radius: 8px; font-weight: 700; font-size: 0.95rem;">
@activeSeason.CtaText
</div>
<div style="background: transparent; border: 2px solid rgba(255,255,255,0.5); color: white; padding: 10px 20px; border-radius: 8px; font-size: 0.95rem;">
서비스 안내
</div>
</div>
</div>
<MudGrid Spacing="2">
<MudItem xs="6">
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">활성 시즌 키</MudText>
<MudText><code>@activeSeason.Key</code></MudText>
</MudItem>
<MudItem xs="6">
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">마감까지</MudText>
<MudText>
@if (activeSeason.DaysUntilDeadline >= 0)
{
<MudChip T="string" Size="Size.Small"
Color="@(activeSeason.DaysUntilDeadline <= 7 ? Color.Error : Color.Warning)">
D-@activeSeason.DaysUntilDeadline
</MudChip>
}
else
{
<span>마감 후 @(-activeSeason.DaysUntilDeadline)일</span>
}
</MudText>
</MudItem>
<MudItem xs="6">
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">포커스 서비스</MudText>
<MudText>@activeSeason.FocusService</MudText>
</MudItem>
<MudItem xs="6">
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">블로그 카테고리</MudText>
<MudText>@activeSeason.RelatedCategorySlug</MudText>
</MudItem>
<MudItem xs="12">
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">긴박감 배지 문구</MudText>
<MudText><code>@activeSeason.UrgencyBadge</code></MudText>
</MudItem>
</MudGrid>
}
else
{
<MudAlert Severity="Severity.Info">
선택한 날짜(@(simulationDate?.ToString("MM월 dd일") ?? "-"))는 시즌 비활성 기간입니다.
홈페이지는 기본 Hero를 표시합니다.
</MudAlert>
<div style="background: linear-gradient(135deg, #1a365d 0%, #2a4365 100%); border-radius: 12px; padding: 2rem; color: white; margin-top: 1.5rem;">
<div style="font-size: 1.8rem; font-weight: 800; margin-bottom: 0.5rem;">
사업자 세금, 부동산,<br/>가족자산까지
</div>
<div style="font-size: 0.95rem; color: rgba(255,255,255,0.8); margin-bottom: 1.5rem;">
세무사·부동산중개사·보험설계사 자격 보유 | 온라인 맞춤 상담
</div>
<div style="background: #e53e3e; color: white; display: inline-block; padding: 10px 20px; border-radius: 8px; font-weight: 700;">
무료 상담 신청
</div>
</div>
}
</MudPaper>
<MudPaper Class="pa-4 mt-4" Elevation="1">
<MudText Typo="Typo.h6" Class="mb-3">연간 시즌 타임라인</MudText>
<MudSimpleTable Dense="true">
<thead>
<tr>
<th>기간</th>
<th>시즌</th>
<th>블로그 카테고리</th>
<th>상태</th>
</tr>
</thead>
<tbody>
@foreach (var s in TaxSeasonCalendar.Seasons)
{
var isActive = activeSeason?.Key == s.Key;
<tr style="@(isActive ? "background: rgba(66,153,225,0.1);" : "")">
<td style="white-space: nowrap;">
@s.StartMonth/@s.StartDay ~ @s.EndMonth/@s.EndDay
</td>
<td>@s.Name</td>
<td><code style="font-size:0.8rem;">@s.RelatedCategorySlug</code></td>
<td>
@if (isActive)
{
<MudChip T="string" Size="Size.Small" Color="Color.Success">활성</MudChip>
}
else
{
<span style="color: #a0aec0; font-size: 0.85rem;">비활성</span>
}
</td>
</tr>
}
</tbody>
</MudSimpleTable>
</MudPaper>
</MudItem>
</MudGrid>
@code {
private DateTime? simulationDate = DateTime.Today;
private CurrentSeasonDto? activeSeason;
protected override void OnInitialized() => ComputeSeason();
private void ComputeSeason()
{
if (simulationDate == null) { activeSeason = null; return; }
var date = simulationDate.Value;
var season = TaxSeasonCalendar.Seasons.FirstOrDefault(s =>
{
var start = new DateTime(date.Year, s.StartMonth, s.StartDay);
var endYear = (s.EndMonth < s.StartMonth) ? date.Year + 1 : date.Year;
var end = new DateTime(endYear, s.EndMonth, s.EndDay);
return date >= start && date <= end;
});
if (season == null) { activeSeason = null; return; }
var endYearCalc = (season.EndMonth < season.StartMonth) ? date.Year + 1 : date.Year;
var deadline = new DateTime(endYearCalc, season.EndMonth, season.EndDay);
var ddays = (deadline.Date - date.Date).Days;
var badge = ddays <= 7 && ddays >= 0
? season.UrgencyBadge.Replace("{n}", ddays.ToString())
: season.UrgencyBadge;
activeSeason = new CurrentSeasonDto
{
Key = season.Key,
Name = season.Name,
HeroHeadline = season.HeroHeadline,
HeroSubtext = season.HeroSubtext,
UrgencyBadge = badge,
FocusService = season.FocusService,
RelatedCategorySlug = season.RelatedCategorySlug,
CtaText = season.CtaText,
DaysUntilDeadline = ddays,
Deadline = deadline
};
}
private void JumpToSeason(TaxSeason season)
{
simulationDate = new DateTime(DateTime.Today.Year, season.StartMonth, season.StartDay);
ComputeSeason();
}
}