[] 사이드 뷰 개발

This commit is contained in:
SEAN-59 2025-07-03 21:16:55 +09:00
parent 3cbe24216d
commit 6342324108
7 changed files with 120 additions and 24 deletions

View File

@ -51,7 +51,8 @@ builder.Services.AddScoped<SecureService>();
builder.Services.AddScoped<StorageService>();
builder.Services.AddScoped<QueryParamService>();
builder.Services.AddScoped<LoadingService>();
builder.Services.AddScoped<UserStateService>();
builder.Services.AddSingleton<UserStateService>();
// builder.Services.AddSingleton<LoggerService>(sp

View File

@ -13,6 +13,9 @@ public partial class MainLayout : LayoutComponentBase, IDisposable
[Inject] NavigationManager Navigation { get; set; } = default!;
[Inject] LoadingService LoadingService { get; set; } = default!;
[Inject] UserStateService UserStateService { get; set; } = default!;
private bool _isLoading = false;
// 경로의 시작 부분
// protected bool isHidePrjTop => Navigation.ToBaseRelativePath(Navigation.Uri).StartsWith("auth", StringComparison.OrdinalIgnoreCase);
@ -28,23 +31,50 @@ public partial class MainLayout : LayoutComponentBase, IDisposable
protected override async Task OnInitializedAsync()
{
LoggerService.Write("MainLayout OnInitializedAsync 시작");
LoadingService.OnChange += StateHasChanged;
Navigation.LocationChanged += HandleLocationChanged;
HandleLocationChanged(this, new LocationChangedEventArgs(Navigation.Uri, false));
LoggerService.Write("MainLayout: UserStateService.GetUserDataAsync 호출 전");
await UserStateService.GetUserDataAsync();
LoggerService.Write($"MainLayout: UserStateService.isLogin 상태: {UserStateService.isLogin}");
// 학원 정보 로드 및 실패 시 처리
var academyResult = await UserStateService.GetAcademy();
LoadingService.ShowLoading();
if (academyResult.success)
{
if (academyResult.simpleAcademy != null && academyResult.simpleAcademy.Any())
{
UserStateService.academyItems = academyResult.simpleAcademy.ToArray();
LoggerService.Write($"MainLayout: academyItems 로드 성공. {UserStateService.academyItems.Length}개");
}
else
{
LoggerService.Write("MainLayout: 로드된 학원 정보가 없습니다.");
}
}
else
{
LoggerService.Write("MainLayout: 서버 세션에서 학원 정보 불러오기 실패. 사용자 상태 초기화.");
await UserStateService.ClearUserStateAsnyc();
}
if (isAcademy)
{
if(!UserStateService.isLogin || UserStateService.UserData == null)
{
LoggerService.Write("로그인 상태가 아닙니다. 초기로 돌립니다.");
if (isIntro)
{
} //await UserStateService.ClearUserStateAsnyc();
if (isIntro) { }
else
{
await UserStateService.ClearUserStateAsnyc();
LoadingService.HideLoading();
Navigation.NavigateTo("/");
}
}
LoadingService.HideLoading();
}
}

View File

@ -2,16 +2,40 @@ using System.Text.Json;
using Front.Program.Services;
using Front.Program.Models;
using Microsoft.JSInterop;
using System.ComponentModel; // INotifyPropertyChanged를 위해 추가
using System.Runtime.CompilerServices; // CallerMemberName을 위해 추가
namespace Front.Program.ViewModels;
public class UserStateService(StorageService _storageService, SecureService _secureService, APIService _APIService,
IJSRuntime _js)
IJSRuntime _js) : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private Models.SimpleAcademy? _currentAcademy;
public Models.SimpleAcademy? CurrentAcademy
{
get => _currentAcademy;
set
{
if (_currentAcademy != value)
{
_currentAcademy = value;
OnPropertyChanged();
}
}
}
public UserData UserData { get; set; } = new UserData();
public bool isFirstCheck { get; set; } = false;
public bool isLogin { get; set; } = false;
public Models.SimpleAcademy[] academyItems = Array.Empty<Models.SimpleAcademy>();
@ -52,12 +76,17 @@ public class UserStateService(StorageService _storageService, SecureService _sec
try
{
LoggerService.Write("GetUserDataAsync 호출됨");
// 로그인 상태가 아니라면 애초에 할 필요 없음
if (await _storageService.GetItemAsync("IsLogin") != "true")
var isLoginFromStorage = await _storageService.GetItemAsync("IsLogin");
LoggerService.Write($"Storage에서 읽은 IsLogin 값: {isLoginFromStorage ?? "null"}");
// 로그인 상태가 아니라면 애초에 할 필요 없음
if (isLoginFromStorage != "true")
{
isLogin = false;
return false;
}
isLogin = true;
var userDataForm = await GetUserDataFromStorageAsync();
@ -65,7 +94,6 @@ public class UserStateService(StorageService _storageService, SecureService _sec
{
// 사용자 데이터가 성공적으로 로드되었을 때의 로직
UserData = userDataForm.userData;
isLogin = true;
return true;
}
else
@ -75,7 +103,6 @@ public class UserStateService(StorageService _storageService, SecureService _sec
{
// 서버에서 사용자 데이터를 성공적으로 로드했을 때의 로직
UserData = userDataFromServer.userData;
isLogin = true;
return true;
}
else
@ -130,7 +157,14 @@ public class UserStateService(StorageService _storageService, SecureService _sec
{
var data = await _APIService.GetConnectServerAsnyc<List<SimpleAcademy>>("/api/v1/in/user/academy");
if (data is { success: true, json: not null })
{
await _storageService.SetItemAsync("UsAcDt", data.json);
if (data.data != null && data.data.Any())
{
academyItems = data.data.ToArray();
CurrentAcademy = data.data.First(); // 첫 번째 학원을 현재 학원으로 설정
}
}
return (data.success, data.data);
}
}

View File

@ -5,9 +5,9 @@
</div>
<div>
<!-- 회원 이름이 오는 곳 -->
<div class="text-gray-900 text-base font-medium">AcaMate</div>
<div class="text-gray-900 text-base font-medium">@UserName</div>
<!-- 회원 유형이 올 곳 -->
<p class="text-gray-600 text-sm">Parent</p>
<p class="text-gray-600 text-sm">@UserType</p>
</div>
</div>
</div>

View File

@ -1,7 +1,13 @@
using Front.Program.ViewModels;
using Microsoft.AspNetCore.Components;
namespace Front.Program.Views.Academy.Common;
public partial class LeftSideAcademy : ComponentBase
{
}
[Inject]
private UserStateService UserStateService { get; set; }
private string UserName => UserStateService.UserData?.Name ?? "AcaMate";
private string UserType => UserStateService.UserData?.Type ?? "Parent";
}

View File

@ -2,7 +2,7 @@
<div id="AcademyDrop" class="relative flex items-center gap-4 text-[#111418] flex-1">
<button class="flex items-center gap-2 hover:text-blue-600" @onclick="ToggleAcademyDropdown">
<h2 class="hidden md:block text-text-title text-lg font-bold leading-tight tracking-[-0.015em]">AcaMate</h2>
<h2 class="hidden md:block text-text-title text-lg font-bold leading-tight tracking-[-0.015em]">@currentAcademyName</h2>
<img src="Resources/Images/Icon/Down.png" alt="아래"
class="w-6 h-6 object-cover transition-transform duration-200 @(isAcademyDropdownOpen ? "rotate-180" : "")" />
</button>
@ -10,15 +10,12 @@
@if (isAcademyDropdownOpen)
{
<div class="absolute top-full left-0 mt-2 w-64 bg-white rounded-lg shadow-lg py-2 z-50">
<div class="px-4 py-2 border-b border-gray-200">
<h3 class="font-semibold text-gray-900">학원 정보</h3>
</div>
<div class="max-h-60 overflow-y-auto">
@foreach (var academy in academyItems)
{
<a href="/am/@academy.bid" class="block px-4 py-2 text-text-title hover:bg-gray-100">
<div @onclick="() => SelectAcademy(academy)" class="cursor-pointer block px-4 py-2 text-text-title hover:bg-gray-100">
@academy.name
</a>
</div>
}
</div>
</div>
@ -45,4 +42,4 @@
</div>
</div>
</div>
</div>
</div>

View File

@ -1,3 +1,5 @@
using System.ComponentModel;
using Front.Program.ViewModels;
using Front.Program.Services;
using Microsoft.AspNetCore.Components;
@ -8,26 +10,52 @@ using Front.Program.Models;
namespace Front.Program.Views.Academy.Common;
public partial class TopNavAcademy : ComponentBase
public partial class TopNavAcademy : ComponentBase, IDisposable
{
[Inject] UserStateService UserStateService { get; set; } = default!;
[Inject] NavigationManager NavigationManager { get; set; } = default!;
protected bool isOpen = false;
protected bool isAcademyDropdownOpen = false;
protected Models.SimpleAcademy[] academyItems = Array.Empty<Models.SimpleAcademy>();
// 계산된 속성으로 변경
protected Models.SimpleAcademy[] academyItems => UserStateService.academyItems;
protected string currentAcademyName => UserStateService.CurrentAcademy?.name ?? "학원을 선택하세요";
protected override async Task OnInitializedAsync()
protected override void OnInitialized()
{
LoggerService.Write("TOPNAV_OnInitializedAsync");
UserStateService.PropertyChanged += OnUserStateServicePropertyChanged;
}
public void Dispose()
{
UserStateService.PropertyChanged -= OnUserStateServicePropertyChanged;
}
private void OnUserStateServicePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(UserStateService.CurrentAcademy))
{
StateHasChanged();
}
}
protected void ToggleAcademyDropdown() {
isAcademyDropdownOpen = !isAcademyDropdownOpen;
}
private void SelectAcademy(SimpleAcademy academy)
{
UserStateService.CurrentAcademy = academy; // 현재 선택된 학원 업데이트
isAcademyDropdownOpen = false;
NavigationManager.NavigateTo($"/am/main?bid={academy.bid}");
}
private void OnClickOutside()
{
if (isAcademyDropdownOpen) isAcademyDropdownOpen = false;
StateHasChanged();
}
}
}