forked from AcaMate/AcaMate_Web
[✨] am/Intro 화면 동작 구현
1. 로그인 연동 2. 화면 변환 연동 2.1. 아직 Academy 테이블 연동은 안되어있는 상황
This commit is contained in:
parent
2665dcbf64
commit
3e31f9f46b
|
@ -27,6 +27,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Program\ViewModels\" />
|
||||
<Folder Include="Program\Views\Project\FooterLink\" />
|
||||
<Folder Include="wwwroot\Resources\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -37,11 +37,8 @@ builder.Services.AddScoped<APIService>();
|
|||
builder.Services.AddScoped<SecureService>();
|
||||
builder.Services.AddScoped<StorageService>();
|
||||
builder.Services.AddScoped<QueryParamService>();
|
||||
// builder.Services.AddRazorPages();
|
||||
// builder.Services.AddServerSideBlazor();
|
||||
builder.Services.AddScoped<LoadingService>();
|
||||
builder.Services.AddScoped<UserService>();
|
||||
|
||||
builder.Services.AddScoped<UserViewModel>();
|
||||
builder.Services.AddScoped<LoadingService>();
|
||||
builder.Services.AddScoped<UserStateService>();
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
|
|
|
@ -9,18 +9,26 @@
|
|||
@if(isAcademy)
|
||||
{
|
||||
<div class="flex flex-1 flex-col md:flex-row">
|
||||
<div class="hidden md:block w-64 bg-white shadow-lg border-r border-gray-200 fixed top-0 bottom-0">
|
||||
<LeftSideAcademy />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 flex-col md:ml-64">
|
||||
<div class="fixed top-0 right-0 left-64 z-10">
|
||||
<TopNavAcademy />
|
||||
@if (!isIntro && UserStateService.isLogin)
|
||||
{
|
||||
<div class="hidden md:block w-64 bg-white shadow-lg border-r border-gray-200 fixed top-0 bottom-0">
|
||||
<LeftSideAcademy/>
|
||||
</div>
|
||||
<div class="flex-1 mt-16">
|
||||
<div class="flex flex-1 flex-col md:ml-64">
|
||||
<div class="fixed top-0 right-0 left-64 z-10">
|
||||
<TopNavAcademy/>
|
||||
</div>
|
||||
<div class="flex-1 mt-16">
|
||||
@Body
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<main class="flex-1 w-full w-max-960 mx-auto">
|
||||
@Body
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
|
|
|
@ -4,26 +4,24 @@ using Microsoft.AspNetCore.Components.Routing;
|
|||
using Front.Program.Views.Project;
|
||||
using Front.Program.Views.Academy;
|
||||
using Front.Program.Services;
|
||||
using Front.Program.ViewModels;
|
||||
|
||||
namespace Front.Program.Layout;
|
||||
|
||||
public partial class MainLayout : LayoutComponentBase, IDisposable
|
||||
{
|
||||
[Inject]
|
||||
NavigationManager Navigation { get; set; } = default!;
|
||||
|
||||
[Inject]
|
||||
LoadingService LoadingService { get; set; } = default!;
|
||||
|
||||
[Inject]
|
||||
StorageService StorageService { get; set; } = default!;
|
||||
[Inject] NavigationManager Navigation { get; set; } = default!;
|
||||
[Inject] LoadingService LoadingService { get; set; } = default!;
|
||||
[Inject] UserStateService UserStateService { get; set; } = default!;
|
||||
|
||||
// 경로의 시작 부분
|
||||
// protected bool isHidePrjTop => Navigation.ToBaseRelativePath(Navigation.Uri).StartsWith("auth", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// 경로의 끝 부분
|
||||
protected bool isHidePrjTop => Navigation.ToBaseRelativePath(Navigation.Uri).EndsWith("auth", StringComparison.OrdinalIgnoreCase);
|
||||
protected bool isAcademy => Navigation.ToBaseRelativePath(Navigation.Uri).StartsWith("am", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// 경로 일치
|
||||
protected bool isIntro => Navigation.ToBaseRelativePath(Navigation.Uri).Equals("am/intro", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
|
@ -36,37 +34,6 @@ public partial class MainLayout : LayoutComponentBase, IDisposable
|
|||
private async void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
{
|
||||
LoadingService.HideNavigationLoading();
|
||||
//
|
||||
// var uri = Navigation.ToAbsoluteUri(Navigation.Uri);
|
||||
// Console.WriteLine($"리다이렉트된 URI: {uri}");
|
||||
//
|
||||
// if (uri.Query.Contains("auth="))
|
||||
// {
|
||||
// var query = uri.Query.TrimStart('?');
|
||||
// var parameters = query.Split('&')
|
||||
// .Select(p => p.Split('='))
|
||||
// .Where(p => p.Length == 2)
|
||||
// .ToDictionary(p => p[0], p => p[1]);
|
||||
//
|
||||
// if (parameters.TryGetValue("auth", out var auth))
|
||||
// {
|
||||
// Console.WriteLine($"auth 파라미터 값: {auth}");
|
||||
// if (auth == "true")
|
||||
// {
|
||||
// await StorageService.SetItemAsync("IsLogin", "true");
|
||||
// Console.WriteLine("로그인 상태를 true로 설정했습니다.");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// await StorageService.RemoveItemAsync("IsLogin");
|
||||
// Console.WriteLine("로그인 상태를 제거했습니다.");
|
||||
// }
|
||||
//
|
||||
// // 파라미터를 제거하고 리다이렉트
|
||||
// var baseUri = uri.GetLeftPart(UriPartial.Path);
|
||||
// Navigation.NavigateTo(baseUri, forceLoad: false);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
22
Program/Models/AcademyModels.cs
Normal file
22
Program/Models/AcademyModels.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Front.Program.Models;
|
||||
|
||||
public class Academy
|
||||
{
|
||||
public required string bid { get; set; }
|
||||
public string business_name { get; set; } = string.Empty;
|
||||
public string business_owner { get; set; } = string.Empty;
|
||||
public string businessOwnerUID { get; set; } = string.Empty;
|
||||
public string business_number { get; set; } = string.Empty;
|
||||
public DateTime business_date { get; set; }
|
||||
public string business_address { get; set; } = string.Empty;
|
||||
public string business_contact { get; set; } = string.Empty;
|
||||
public string uid { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SimpleAcademy
|
||||
{
|
||||
public required string bid { get; set; }
|
||||
public string business_name { get; set; } = string.Empty;
|
||||
}
|
|
@ -1,20 +1,21 @@
|
|||
using Front.Program.Views.Project;
|
||||
// using Front.Program.Views.Project.Common;
|
||||
|
||||
using Front.Program.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Front.Program.Services;
|
||||
// 뷰를 참조 안하고도 로딩 상태를 알 수 있게 바꾸기
|
||||
|
||||
public class LoadingService
|
||||
{
|
||||
public bool IsLoading { get; private set; }
|
||||
public IndicateType CurrentType { get; private set; } = IndicateType.Page;
|
||||
private bool isNavigationLoading { get; set; }
|
||||
|
||||
public event Action? OnChange;
|
||||
|
||||
public void ShowLoading(IndicateType type = IndicateType.Page, bool isNavigation = false)
|
||||
public void ShowLoading(bool isNavigation = false)
|
||||
{
|
||||
IsLoading = true;
|
||||
CurrentType = type;
|
||||
isNavigationLoading = isNavigation;
|
||||
NotifyStateChanged();
|
||||
}
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
using System.Text.Json;
|
||||
using Front.Program.Models;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Front.Program.Services;
|
||||
|
||||
public class UserService
|
||||
{
|
||||
private readonly StorageService _storageService;
|
||||
private readonly SecureService _secureService;
|
||||
private readonly IJSRuntime _js;
|
||||
private readonly ILogger<UserService> _logger;
|
||||
|
||||
public UserService(
|
||||
StorageService storageService,
|
||||
SecureService secureService,
|
||||
IJSRuntime js,
|
||||
ILogger<UserService> logger)
|
||||
{
|
||||
_storageService = storageService;
|
||||
_secureService = secureService;
|
||||
_js = js;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
public async Task<(bool success, UserData? userData)> GetUserData()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1. 먼저 저장된 데이터 확인
|
||||
var encryptedUserData = await _storageService.GetItemAsync("USER_DATA");
|
||||
if (!string.IsNullOrEmpty(encryptedUserData))
|
||||
{
|
||||
try
|
||||
{
|
||||
var decryptedUserData = await _secureService.DecryptAsync(encryptedUserData);
|
||||
var userData = JsonSerializer.Deserialize<UserData>(decryptedUserData);
|
||||
if (userData != null && !string.IsNullOrEmpty(userData.Name))
|
||||
{
|
||||
_logger.LogInformation("저장된 사용자 데이터 로드 성공");
|
||||
return (true, userData);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning($"저장된 사용자 데이터 복호화 실패: {ex.Message}");
|
||||
await _storageService.RemoveItemAsync("USER_DATA");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. API 호출
|
||||
var headerValue = await _storageService.GetItemAsync("Web_AM_Connect_Key");
|
||||
if (string.IsNullOrEmpty(headerValue))
|
||||
{
|
||||
_logger.LogWarning("연결 키가 없습니다");
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
_logger.LogInformation("세션 API 호출 시작");
|
||||
var response = await _js.InvokeAsync<JsonElement>("fetchWithHeaderAndReturnUrl",
|
||||
"/api/v1/in/user/auth/session",
|
||||
"GET",
|
||||
"Web_AM_Connect_Key",
|
||||
headerValue);
|
||||
|
||||
if (response.TryGetProperty("data", out var dataElement))
|
||||
{
|
||||
try
|
||||
{
|
||||
// 전체 데이터 암호화 저장
|
||||
var userDataJson = dataElement.ToString();
|
||||
var userData = JsonSerializer.Deserialize<UserData>(userDataJson);
|
||||
|
||||
if (userData != null && !string.IsNullOrEmpty(userData.Name))
|
||||
{
|
||||
var encryptedData = await _secureService.EncryptAsync(userDataJson);
|
||||
await _storageService.SetItemAsync("USER_DATA", encryptedData);
|
||||
await _storageService.SetItemAsync("Web_AM_Connect_Key", headerValue);
|
||||
|
||||
_logger.LogInformation($"사용자 데이터 저장 성공: {userData.Name}");
|
||||
return (true, userData);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("사용자 데이터에 필수 정보가 없습니다");
|
||||
return (false, null);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"사용자 데이터 처리 중 오류: {ex.Message}");
|
||||
return (false, null);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogWarning("사용자 데이터를 찾을 수 없습니다");
|
||||
return (false, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"사용자 데이터 조회 중 오류: {ex.Message}");
|
||||
return (false, null);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ClearUserData()
|
||||
{
|
||||
try
|
||||
{
|
||||
await _storageService.RemoveItemAsync("USER_DATA");
|
||||
await _storageService.RemoveItemAsync("USER");
|
||||
await _storageService.RemoveItemAsync("Web_AM_Connect_Key");
|
||||
_logger.LogInformation("사용자 데이터 삭제 성공");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"사용자 데이터 삭제 중 오류: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,12 +5,14 @@ using Microsoft.JSInterop;
|
|||
|
||||
namespace Front.Program.ViewModels;
|
||||
|
||||
public class UserViewModel(StorageService _storageService,SecureService _secureService, IJSRuntime _js)
|
||||
public class UserStateService(StorageService _storageService,SecureService _secureService, IJSRuntime _js)
|
||||
{
|
||||
public UserData UserData { get; set; } = new UserData();
|
||||
|
||||
public bool isFirstCheck { get; set; } = false;
|
||||
public bool isLogin { get; set; } = false;
|
||||
|
||||
|
||||
public async Task<(bool success, UserData? userData)> GetUserDataFromStorageAsync()
|
||||
{
|
||||
try
|
||||
|
@ -101,41 +103,48 @@ public class UserViewModel(StorageService _storageService,SecureService _secureS
|
|||
|
||||
public async Task<bool> GetUserDataAsync()
|
||||
{
|
||||
Console.WriteLine("GetUserDataAsync 호출됨");
|
||||
// 로그인 상태가 아니라면 애초에 할 필요 없음
|
||||
if (await _storageService.GetItemAsync("IsLogin") != "true")
|
||||
try
|
||||
{
|
||||
isLogin = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
var userDataForm = await GetUserDataFromStorageAsync();
|
||||
|
||||
if (userDataForm.success && userDataForm.userData != null)
|
||||
{
|
||||
// 사용자 데이터가 성공적으로 로드되었을 때의 로직
|
||||
UserData = userDataForm.userData;
|
||||
isLogin = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var userDataFromServer = await GetUserDataFromServerAsync();
|
||||
if (userDataFromServer.success && userDataFromServer.userData != null)
|
||||
Console.WriteLine("GetUserDataAsync 호출됨");
|
||||
// 로그인 상태가 아니라면 애초에 할 필요 없음
|
||||
if (await _storageService.GetItemAsync("IsLogin") != "true")
|
||||
{
|
||||
// 서버에서 사용자 데이터를 성공적으로 로드했을 때의 로직
|
||||
UserData = userDataFromServer.userData;
|
||||
isLogin = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
var userDataForm = await GetUserDataFromStorageAsync();
|
||||
|
||||
if (userDataForm.success && userDataForm.userData != null)
|
||||
{
|
||||
// 사용자 데이터가 성공적으로 로드되었을 때의 로직
|
||||
UserData = userDataForm.userData;
|
||||
isLogin = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 사용자 데이터를 로드하지 못했을 때의 로직
|
||||
Console.WriteLine("사용자 데이터를 로드하지 못했습니다.");
|
||||
isLogin = false;
|
||||
return false;
|
||||
var userDataFromServer = await GetUserDataFromServerAsync();
|
||||
if (userDataFromServer.success && userDataFromServer.userData != null)
|
||||
{
|
||||
// 서버에서 사용자 데이터를 성공적으로 로드했을 때의 로직
|
||||
UserData = userDataFromServer.userData;
|
||||
isLogin = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 사용자 데이터를 로드하지 못했을 때의 로직
|
||||
Console.WriteLine("사용자 데이터를 로드하지 못했습니다.");
|
||||
isLogin = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!isFirstCheck) isFirstCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ClearUserData()
|
|
@ -1,29 +1,67 @@
|
|||
@page "/am/intro"
|
||||
|
||||
<div class="relative flex size-full min-h-screen flex-col bg-white group/design-root overflow-x-hidden" style='font-family: "Public Sans", "Noto Sans", sans-serif;'>
|
||||
<div class="relative flex size-full min-h-screen flex-col bg-normal-normal group/design-root overflow-x-hidden" style='font-family: "Public Sans", "Noto Sans", sans-serif;'>
|
||||
<div class="layout-container flex h-full grow flex-col">
|
||||
<div class="px-40 flex flex-1 justify-center py-5">
|
||||
<div class="px-4 sm:px-6 md:px-10 lg:px-24 xl:px-40 flex flex-1 justify-center py-5">
|
||||
<div class="layout-content-container flex flex-col max-w-[960px] flex-1">
|
||||
<div class="w-full" style="height: 100px;"></div>
|
||||
<div class="container">
|
||||
<div class="px-4 py-3">
|
||||
<div
|
||||
class="w-full bg-center bg-no-repeat bg-cover flex flex-col justify-end overflow-hidden bg-white rounded-xl min-h-[218px]"
|
||||
style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuBDQ6ItFmMNXPyz0TZ_MJfBxzunRwfPEo5gf23eHqM80NCcy7sZgfhQgiCTCOX3u8_Ecpx5oRkoRsGCPzZY4Mciglrr0-n7SqyJnM6XJgCJ4sy9a6dSP5AXQVMpa3StypgUdTxSWkIFH1QQddb_7HOqqQazEwH7x_dSKrr-FHUF1EfvLihJD210rH0QjgBxdaEhHpKsJVUEa_OrRZ30VF5yADD9xDz05g_bwHcGOPXlWnVERJldx6hc-eEFHwR483kVmiSSRODPv4XC");'
|
||||
></div>
|
||||
<div class="container pt-24">
|
||||
<div class="px-4 md:px-8 py-4">
|
||||
<div class="w-full bg-center bg-no-repeat bg-contain md:bg-contain flex flex-col justify-center items-center overflow-hidden bg-white/35 rounded-xl min-h-[218px] md:h-[300px]"
|
||||
style="background-image: url('/Resources/Images/Logo/Crystal_Icon.png');">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="text-[#111518] tracking-light text-2xl font-bold leading-tight px-4 text-center pb-2 pt-5">학원을 위한 통합 플랫폼</h3>
|
||||
<div class="flex px-4 py-3 justify-center">
|
||||
<button
|
||||
class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-xl h-12 px-5 bg-[#1990e5] text-white text-base font-bold leading-normal tracking-[0.015em]"
|
||||
>
|
||||
<span class="truncate">시작하기</span>
|
||||
</button>
|
||||
|
||||
@if (!UserStateService.isLogin)
|
||||
{
|
||||
<h3 class="text-[#111518] tracking-light text-2xl font-bold leading-tight px-4 text-center pb-2 pt-3">
|
||||
학원을 위한 통합 플랫폼
|
||||
</h3>
|
||||
|
||||
<div class="flex px-4 py-2 justify-center">
|
||||
<button class="bg-second-normal hover:bg-second-hover transition-all duration-200 shadow-md text-white font-bold py-3 px-6 rounded-xl"
|
||||
@onclick="OnClickLogin">
|
||||
<span class="truncate">시작하기</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="flex flex-col px-4 py-2 gap-2">
|
||||
<h3 class="text-[#111518] tracking-light text-xl font-bold leading-tight text-center py-12">
|
||||
@UserStateService.UserData.Name 님, 안녕하세요!<br />
|
||||
학원을 선택해주세요.<br />
|
||||
</h3>
|
||||
<div class="max-h-[180px] overflow-y-auto rounded-xl bg-second-normal/10 border-2 border-text-detail">
|
||||
@foreach (var academy in academyItems)
|
||||
{
|
||||
<a href="/am/@academy.bid"
|
||||
class="block w-full px-4 py-3 hover:bg-second-dark border-b border-gray-200 last:border-b-0 group">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-text-black group-hover:text-text-white font-medium">@academy.business_name</span>
|
||||
<svg class="w-5 h-5 text-text-detail group-hover:text-text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* <div class="w-full" style="height: 100px;"></div> *@
|
||||
<div class="border-b border-text-disabled my-4 pt-12"></div>
|
||||
<div class="flex flex-col md:flex-row justify-center items-center gap-4 px-4">
|
||||
<a href="/terms" class="text-text-detail text-sm font-normal leading-normal hover:text-text-black hover:font-bold">이용약관</a>
|
||||
<span class="hidden md:inline text-text-black">·</span>
|
||||
<a href="/privacy" class="text-text-detail text-sm font-normal leading-normal hover:text-text-black hover:font-bold">개인정보처리방침</a>
|
||||
<span class="hidden md:inline text-text-black">·</span>
|
||||
<a href="/contact" class="text-text-detail text-sm font-normal leading-normal hover:text-text-black hover:font-bold">문의하기</a>
|
||||
</div>
|
||||
<div class="w-full" style="height: 100px;"></div>
|
||||
<p class="text-[#637888] text-sm font-normal leading-normal pb-3 pt-1 px-4 text-center">Terms of Service · Privacy Policy · Contact Us</p>
|
||||
<p class="text-[#637888] text-sm font-normal leading-normal pb-3 pt-1 px-4 text-center">© 2024 AcaMate. All rights reserved.</p>
|
||||
|
||||
<p class="text-text-detail text-sm font-normal leading-normal py-4 px-4 text-center">
|
||||
© 2024 AcaMate. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,88 @@
|
|||
using Front.Program.Models;
|
||||
using Front.Program.Services;
|
||||
using Front.Program.ViewModels;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
|
||||
namespace Front.Program.Views.Academy;
|
||||
|
||||
public partial class AcademyIntro : ComponentBase
|
||||
public partial class AcademyIntro : ComponentBase, IDisposable
|
||||
{
|
||||
[Inject] NavigationManager Navigation { get; set; } = default!;
|
||||
[Inject] StorageService StorageService { get; set; } = default!;
|
||||
[Inject] QueryParamService QueryParamService { get; set; } = default!;
|
||||
[Inject] UserStateService UserStateService { get; set; } = default!;
|
||||
|
||||
private bool _isProcessing = false;
|
||||
|
||||
|
||||
protected Models.SimpleAcademy[] academyItems = Array.Empty<Models.SimpleAcademy>();
|
||||
|
||||
protected override async void OnInitialized()
|
||||
{
|
||||
Navigation.LocationChanged += HandleLocationChanged;
|
||||
HandleLocationChanged(this, new LocationChangedEventArgs(Navigation.Uri, false));
|
||||
if (!UserStateService.isFirstCheck) await UserStateService.GetUserDataAsync();
|
||||
|
||||
academyItems = new[]
|
||||
{
|
||||
new SimpleAcademy{ bid = "AA0000", business_name = "테스트 학원1"},
|
||||
new SimpleAcademy{ bid = "AA0001", business_name = "테스트 학원2"},
|
||||
new SimpleAcademy{ bid = "AA0002", business_name = "테스트 학원3"},
|
||||
new SimpleAcademy{ bid = "AA0003", business_name = "테스트 학원4"},
|
||||
new SimpleAcademy{ bid = "AA0004", business_name = "테스트 학원5"},
|
||||
new SimpleAcademy{ bid = "AA0005", business_name = "테스트 학원6"},
|
||||
new SimpleAcademy{ bid = "AA0006", business_name = "테스트 학원7"},
|
||||
|
||||
};
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Navigation.LocationChanged -= HandleLocationChanged;
|
||||
}
|
||||
|
||||
private async void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 다중 실행 방지
|
||||
if (_isProcessing) return;
|
||||
_isProcessing = true;
|
||||
|
||||
var uri = Navigation.ToAbsoluteUri(Navigation.Uri);
|
||||
Console.WriteLine($"리다이렉트된 URI: {uri}");
|
||||
|
||||
// 쿼리 파라미터가 있는 경우에만 처리
|
||||
if (!string.IsNullOrEmpty(uri.Query))
|
||||
{
|
||||
var queryParam = QueryParamService.ParseQueryParam(uri);
|
||||
await QueryParamService.AuthCheck(queryParam, StorageService);
|
||||
|
||||
// 유저 정보 확인하는거 (로그인 했으니 값 가져와야지)
|
||||
await UserStateService.GetUserDataAsync();
|
||||
|
||||
// 쿼리 파라미터를 제거한 기본 URI로 리다이렉트
|
||||
var baseUri = uri.GetLeftPart(UriPartial.Path);
|
||||
Console.WriteLine($"리다이렉트할 URI: {baseUri}");
|
||||
await InvokeAsync(StateHasChanged); // StateHasChanged를 호출하여 UI 업데이트
|
||||
Navigation.NavigateTo(baseUri, forceLoad: false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error in HandleLocationChanged: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnClickLogin()
|
||||
{
|
||||
Navigation.NavigateTo("/am/auth");
|
||||
}
|
||||
}
|
|
@ -1,13 +1,36 @@
|
|||
<div class="flex items-center justify-between whitespace-nowrap border-b border-solid border-b-[#f0f2f5] h-[72px] bg-white">
|
||||
<div class="flex items-center gap-4 text-[#111418] ml-4">
|
||||
<h2 class="hidden md:block text-text-title text-lg font-bold leading-tight tracking-[-0.015em]">AcaMate</h2>
|
||||
<div id="AcademyDrop" class="relative flex items-center gap-4 text-[#111418] ml-4">
|
||||
<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>
|
||||
<svg class="w-4 h-4 transition-transform duration-200 @(isAcademyDropdownOpen ? "rotate-180" : "")"
|
||||
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
@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">
|
||||
@academy.business_name
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="hidden md:flex flex-1 justify-둥 gap-8">
|
||||
<div class="hidden md:flex flex-1 justify-end gap-8">
|
||||
<div class="flex flex-1 justify-end gap-8">
|
||||
<div class="flex items-center gap-9">
|
||||
<a class="text-text-title font-medium leading-normal hover:text-blue-600" href="/about">About</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,22 +1,27 @@
|
|||
using Front.Program.ViewModels;
|
||||
using Front.Program.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Net.Http.Json;
|
||||
using System.Runtime.InteropServices.JavaScript;
|
||||
using System.Text.Json;
|
||||
using Front.Program.Models;
|
||||
|
||||
namespace Front.Program.Views.Academy;
|
||||
|
||||
public partial class TopNavAcademy : ComponentBase
|
||||
{
|
||||
[Inject] UserViewModel UserViewModel { get; set; } = default!;
|
||||
[Inject] UserStateService UserStateService { get; set; } = default!;
|
||||
|
||||
|
||||
protected bool isOpen = false;
|
||||
protected bool isAcademyDropdownOpen = false;
|
||||
protected Models.SimpleAcademy[] academyItems = Array.Empty<Models.SimpleAcademy>();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Console.WriteLine("TOPNAV_OnInitializedAsync");
|
||||
|
||||
if (string.IsNullOrEmpty(UserViewModel.UserData.Name))
|
||||
{
|
||||
await UserViewModel.GetUserDataAsync();
|
||||
}
|
||||
}
|
||||
|
||||
protected void ToggleAcademyDropdown() {
|
||||
isAcademyDropdownOpen = !isAcademyDropdownOpen;
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ public partial class About : ComponentBase, IDisposable
|
|||
[Inject]
|
||||
QueryParamService QueryParamService { get; set; } = default!;
|
||||
|
||||
[Inject] UserViewModel UserViewModel { get; set; } = default!;
|
||||
[Inject] UserStateService UserStateService { get; set; } = default!;
|
||||
|
||||
private bool _isProcessing = false;
|
||||
|
||||
|
@ -32,12 +32,6 @@ public partial class About : ComponentBase, IDisposable
|
|||
Navigation.LocationChanged -= HandleLocationChanged;
|
||||
}
|
||||
|
||||
private async Task OnClickEvent()
|
||||
{
|
||||
// NavigationManager.NavigateTo("/redirectpage");
|
||||
Console.WriteLine("Redirecting to redirect page");
|
||||
}
|
||||
|
||||
private async void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
{
|
||||
try
|
||||
|
@ -56,7 +50,7 @@ public partial class About : ComponentBase, IDisposable
|
|||
await QueryParamService.AuthCheck(queryParam, StorageService);
|
||||
|
||||
// 유저 정보 확인하는거 (로그인 했으니 값 가져와야지)
|
||||
await UserViewModel.GetUserDataAsync();
|
||||
await UserStateService.GetUserDataAsync();
|
||||
|
||||
// 쿼리 파라미터를 제거한 기본 URI로 리다이렉트
|
||||
var baseUri = uri.GetLeftPart(UriPartial.Path);
|
||||
|
|
5
Program/Views/Project/Common/PageIndicator.razor
Normal file
5
Program/Views/Project/Common/PageIndicator.razor
Normal file
|
@ -0,0 +1,5 @@
|
|||
<div class="fixed top-0 left-0 w-full h-14 bg-black/70 flex items-center justify-center z-50">
|
||||
<div class="bg-gray-200/80 px-4 py-2 rounded-lg">
|
||||
<div class="animate-spin h-5 w-5 border-2 border-gray-600 border-t-transparent rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
7
Program/Views/Project/Common/PageIndicator.razor.cs
Normal file
7
Program/Views/Project/Common/PageIndicator.razor.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
using Front.Program.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Front.Program.Views.Project.Common;
|
||||
|
||||
public partial class PageIndicator : ComponentBase
|
||||
{ }
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Front.Program.Views.Project;
|
||||
namespace Front.Program.Views.Project.Common;
|
||||
|
||||
public partial class RedirectPage : ComponentBase
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Front.Program.Views.Project;
|
||||
namespace Front.Program.Views.Project.Common;
|
||||
|
||||
public partial class TopBanner : ComponentBase
|
||||
{
|
|
@ -11,7 +11,7 @@
|
|||
<a class="text-text-title font-medium leading-normal hover:text-blue-600" href="/join" @onclick="() => isOpen = !isOpen">Join</a>
|
||||
<a class="text-text-title font-medium leading-normal hover:text-blue-600" href="/new" @onclick="() => isOpen = !isOpen">What's New</a>
|
||||
</div>
|
||||
@if (!UserViewModel.isLogin)
|
||||
@if (!UserStateService.isLogin)
|
||||
{
|
||||
<button class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-second-normal hover:bg-second-dark text-white text-sm font-bold leading-normal tracking-[0.015em] mr-4"
|
||||
@onclick="OnClickLogin">
|
||||
|
@ -47,7 +47,7 @@
|
|||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-600" href="/about" @onclick="() => isOpen = !isOpen">About</a>
|
||||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-600" href="/join" @onclick="() => isOpen = !isOpen">Join</a>
|
||||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-600" href="/new" @onclick="() => isOpen = !isOpen">What's New</a>
|
||||
@if (!UserViewModel.isLogin)
|
||||
@if (!UserStateService.isLogin)
|
||||
{
|
||||
<button class="flex w-full cursor-pointer items-center justify-center rounded-lg h-10 px-4 bg-second-normal hover:bg-second-dark text-white text-sm font-bold leading-normal tracking-[0.015em]"
|
||||
@onclick="OnClickLogin">
|
|
@ -7,13 +7,13 @@ using Front.Program.Models;
|
|||
using Front.Program.Services;
|
||||
using Front.Program.ViewModels;
|
||||
|
||||
namespace Front.Program.Views.Project;
|
||||
namespace Front.Program.Views.Project.Common;
|
||||
|
||||
public partial class TopProjectNav : ComponentBase
|
||||
{
|
||||
[Inject] NavigationManager NavigationManager { get; set; } = default!;
|
||||
|
||||
[Inject] UserViewModel UserViewModel { get; set; } = default!;
|
||||
[Inject] UserStateService UserStateService { get; set; } = default!;
|
||||
|
||||
[Inject] IJSRuntime JS { get; set; } = default!;
|
||||
|
||||
|
@ -25,10 +25,7 @@ public partial class TopProjectNav : ComponentBase
|
|||
{
|
||||
Console.WriteLine("TOPNAV_OnInitializedAsync");
|
||||
|
||||
if (string.IsNullOrEmpty(UserViewModel.UserData.Name))
|
||||
{
|
||||
await UserViewModel.GetUserDataAsync();
|
||||
}
|
||||
if (!UserStateService.isFirstCheck) await UserStateService.GetUserDataAsync();
|
||||
}
|
||||
|
||||
public void OnClickMenuDown()
|
||||
|
@ -50,7 +47,7 @@ public partial class TopProjectNav : ComponentBase
|
|||
|
||||
public async Task OnClickLogout()
|
||||
{
|
||||
await UserViewModel.ClearUserData();
|
||||
await UserStateService.ClearUserData();
|
||||
//
|
||||
// if (await UserViewModel.ClearUserData())
|
||||
// {
|
|
@ -4,10 +4,10 @@
|
|||
<div class="flex flex-col items-center justify-center min-h-screen bg-gray-100">
|
||||
<h1 class="text-2xl font-bold mb-4">로그인</h1>
|
||||
<div class="w-full max-w-xs">
|
||||
@if (NavigationManager.Uri.Contains("/academy/auth"))
|
||||
@if (NavigationManager.Uri.Contains("/am/auth"))
|
||||
{
|
||||
<button type="button" class="w-full mb-4 p-2 rounded focus:outline-none"
|
||||
@onclick="@(() => KakaoLogin("/academy"))" >
|
||||
@onclick="@(() => KakaoLogin("/am/intro"))" >
|
||||
<img src="//k.kakaocdn.net/14/dn/btqCn0WEmI3/nijroPfbpCa4at5EIsjyf0/o.jpg"
|
||||
alt="카카오 로그인"
|
||||
class="rounded w-full transition duration-150 hover:brightness-90" />
|
|
@ -4,7 +4,7 @@ using Front.Program.Services;
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Front.Program.Views.Project;
|
||||
namespace Front.Program.Views.Project.ConnectUser;
|
||||
|
||||
public partial class Auth : ComponentBase, IDisposable
|
||||
{
|
|
@ -7,7 +7,7 @@ using System.Net.Http.Json;
|
|||
using Front.Program.Layout;
|
||||
using Front.Program.Services;
|
||||
|
||||
namespace Front.Program.Views.Project;
|
||||
namespace Front.Program.Views.Project.ConnectUser;
|
||||
|
||||
public partial class Register : ComponentBase
|
||||
{
|
|
@ -1,9 +0,0 @@
|
|||
@if (Type == IndicateType.Page)
|
||||
{
|
||||
<div class="fixed top-0 left-0 w-full h-14 bg-black/70 flex items-center justify-center z-50">
|
||||
<div class="bg-gray-200/80 px-4 py-2 rounded-lg">
|
||||
<div class="animate-spin h-5 w-5 border-2 border-gray-600 border-t-transparent rounded-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Front.Program.Views.Project;
|
||||
|
||||
public partial class PageIndicator : ComponentBase
|
||||
{
|
||||
[Parameter]
|
||||
public IndicateType Type { get; set; } = IndicateType.Page;
|
||||
}
|
||||
|
||||
public enum IndicateType
|
||||
{
|
||||
Page,
|
||||
Circle,
|
||||
Progress
|
||||
}
|
|
@ -5,11 +5,15 @@
|
|||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Http
|
||||
|
||||
@using Microsoft.JSInterop
|
||||
@using Front
|
||||
@using Front.Program.Layout
|
||||
|
||||
@using Front.Program.Views.Project
|
||||
@using Front.Program.Views.Project.Common
|
||||
@using Front.Program.Views.Project.ConnectUser
|
||||
|
||||
@using Front.Program.Views.Academy
|
||||
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user