main #20
|
@ -31,6 +31,9 @@ builder.Services.AddScoped(sp => //new HttpClient
|
||||||
// SCOPED 으로 등록된 서비스는 DI 컨테이너에 등록된 서비스의 인스턴스를 사용합니다.
|
// SCOPED 으로 등록된 서비스는 DI 컨테이너에 등록된 서비스의 인스턴스를 사용합니다.
|
||||||
builder.Services.AddScoped<APIService>();
|
builder.Services.AddScoped<APIService>();
|
||||||
builder.Services.AddScoped<CookieService>();
|
builder.Services.AddScoped<CookieService>();
|
||||||
|
// builder.Services.AddRazorPages();
|
||||||
|
// builder.Services.AddServerSideBlazor();
|
||||||
|
builder.Services.AddScoped<LoadingService>();
|
||||||
|
|
||||||
|
|
||||||
await builder.Build().RunAsync();
|
await builder.Build().RunAsync();
|
||||||
|
|
|
@ -1,31 +1,14 @@
|
||||||
@* @inherits LayoutComponentBase *@
|
@inherits LayoutComponentBase
|
||||||
@* *@
|
@implements IDisposable
|
||||||
@* *@
|
|
||||||
@* <div class="min-h-screen bg-gray-50 text-gray-900"> *@
|
|
||||||
@* <TopBanner /> *@
|
|
||||||
@* <TopNav /> *@
|
|
||||||
@* *@
|
|
||||||
@* <div class="flex flex-1"> *@
|
|
||||||
@* <SideNav /> *@
|
|
||||||
@* *@
|
|
||||||
@* <main class="flex-1 p-6"> *@
|
|
||||||
@* $1$ <!-- Body는 URL 뒤에 입력할 페이지에 따라서 그거에 맞는 @page를 찾아서 열어준다. --> #1# *@
|
|
||||||
@* @Body *@
|
|
||||||
@* </main> *@
|
|
||||||
@* </div> *@
|
|
||||||
@* *@
|
|
||||||
@* <FloatingButton /> *@
|
|
||||||
@* <BottomNav /> *@
|
|
||||||
@* <Footer/> *@
|
|
||||||
@* </div> *@
|
|
||||||
|
|
||||||
@inherits LayoutComponentBase
|
|
||||||
|
|
||||||
<div class="min-h-screen flex flex-col bg-gray-50 text-gray-900">
|
<div class="min-h-screen flex flex-col bg-gray-50 text-gray-900">
|
||||||
|
|
||||||
<!-- Top 영역 -->
|
<!-- Top 영역 -->
|
||||||
@* <TopBanner /> *@
|
@* <TopBanner /> *@
|
||||||
<TopNav />
|
@if (!isHideTop)
|
||||||
|
{
|
||||||
|
<TopNav />
|
||||||
|
}
|
||||||
|
|
||||||
<!-- 본문 영역 -->
|
<!-- 본문 영역 -->
|
||||||
<div class="flex flex-1 flex-col md:flex-row">
|
<div class="flex flex-1 flex-col md:flex-row">
|
||||||
|
@ -48,4 +31,13 @@
|
||||||
<!-- 하단 메뉴 -->
|
<!-- 하단 메뉴 -->
|
||||||
<BottomNav />
|
<BottomNav />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
|
@if (LoadingService.IsLoading)
|
||||||
|
{
|
||||||
|
<div class="fixed inset-0 bg-black/80 flex items-center justify-center z-50">
|
||||||
|
<div class="bg-gray-200/60 px-6 py-4 rounded-lg">
|
||||||
|
<div class="animate-spin h-8 w-8 border-4 border-gray-600 border-t-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
49
Program/Layout/MainLayout.razor.cs
Normal file
49
Program/Layout/MainLayout.razor.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Routing;
|
||||||
|
using Front.Program.Views.Project;
|
||||||
|
using Front.Program.Services;
|
||||||
|
|
||||||
|
namespace Front.Program.Layout;
|
||||||
|
|
||||||
|
public partial class MainLayout : LayoutComponentBase, IDisposable
|
||||||
|
{
|
||||||
|
[Inject]
|
||||||
|
NavigationManager Navigation { get; set; } = default!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
LoadingService LoadingService { get; set; } = default!;
|
||||||
|
|
||||||
|
// protected bool isHideTop => Navigation.Uri.Contains("/auth");
|
||||||
|
protected bool isHideTop => Navigation.ToBaseRelativePath(Navigation.Uri).Equals("auth", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public static bool IsLoading { get; set; }
|
||||||
|
public static IndicateType CurrentType { get; set; } = IndicateType.Page;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
LoadingService.OnChange += StateHasChanged;
|
||||||
|
Navigation.LocationChanged += HandleLocationChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||||
|
{
|
||||||
|
LoadingService.HideNavigationLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
LoadingService.OnChange -= StateHasChanged;
|
||||||
|
Navigation.LocationChanged -= HandleLocationChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ShowLoading(IndicateType type = IndicateType.Page)
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
CurrentType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HideLoading()
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
}
|
42
Program/Services/LoadingService.cs
Normal file
42
Program/Services/LoadingService.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using Front.Program.Views.Project;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
CurrentType = type;
|
||||||
|
isNavigationLoading = isNavigation;
|
||||||
|
NotifyStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HideLoading()
|
||||||
|
{
|
||||||
|
if (!isNavigationLoading)
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
NotifyStateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HideNavigationLoading()
|
||||||
|
{
|
||||||
|
if (isNavigationLoading)
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
isNavigationLoading = false;
|
||||||
|
NotifyStateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyStateChanged() => OnChange?.Invoke();
|
||||||
|
}
|
|
@ -3,8 +3,10 @@
|
||||||
<div class="flex flex-col items-center justify-center min-h-screen bg-gray-100">
|
<div class="flex flex-col items-center justify-center min-h-screen bg-gray-100">
|
||||||
<h1 class="text-2xl font-bold mb-4">로그인</h1>
|
<h1 class="text-2xl font-bold mb-4">로그인</h1>
|
||||||
<div class="w-full max-w-xs">
|
<div class="w-full max-w-xs">
|
||||||
<input type="text" placeholder="아이디" class="mb-4 p-2 border border-gray-300 rounded w-full" />
|
<button type="button" class="w-full mb-4 p-2 rounded focus:outline-none" @onclick="KakaoLogin">
|
||||||
<input type="password" placeholder="비밀번호" class="mb-4 p-2 border border-gray-300 rounded w-full" />
|
<img src="//k.kakaocdn.net/14/dn/btqCn0WEmI3/nijroPfbpCa4at5EIsjyf0/o.jpg"
|
||||||
<button @onclick = "KakaoLogin" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 w-full">로그인</button>
|
alt="카카오 로그인"
|
||||||
|
class="rounded w-full transition duration-150 hover:brightness-90" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,3 +1,6 @@
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Front.Program.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
|
|
||||||
|
@ -6,11 +9,21 @@ namespace Front.Program.Views.Project;
|
||||||
public partial class Auth : ComponentBase
|
public partial class Auth : ComponentBase
|
||||||
{
|
{
|
||||||
[Inject] NavigationManager NavigationManager { get; set; } = default!;
|
[Inject] NavigationManager NavigationManager { get; set; } = default!;
|
||||||
[Inject] IJSRuntime JS { get; set; } = default!;
|
[Inject] LoadingService LoadingService { get; set; } = default!;
|
||||||
void KakaoLogin()
|
// [Inject] IJSRuntime JS { get; set; } = default!;
|
||||||
|
// [Inject] CookieService Cookie { get; set; } = default!;
|
||||||
|
[Inject] HttpClient Http { get; set; } = default!;
|
||||||
|
|
||||||
|
public async Task KakaoLogin()
|
||||||
{
|
{
|
||||||
// await JS
|
LoadingService.ShowLoading();
|
||||||
// Redirect to Kakao login page
|
var url = "/api/v1/out/user/kakao/auth";
|
||||||
NavigationManager.NavigateTo("/api/v1/in/user/kakao/auth", true);
|
var response = await Http.GetFromJsonAsync<JsonElement>(url);
|
||||||
|
var kakaoUrl = response.GetProperty("url").GetString();
|
||||||
|
Console.WriteLine(kakaoUrl);
|
||||||
|
if (!string.IsNullOrEmpty(kakaoUrl))
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(kakaoUrl, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
11
Program/Views/Project/PageIndicator.razor
Normal file
11
Program/Views/Project/PageIndicator.razor
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<h3>PageIndicator</h3>
|
||||||
|
|
||||||
|
@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>
|
||||||
|
}
|
||||||
|
|
16
Program/Views/Project/PageIndicator.razor.cs
Normal file
16
Program/Views/Project/PageIndicator.razor.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
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
|
||||||
|
}
|
128
Program/Views/Project/Register.razor
Normal file
128
Program/Views/Project/Register.razor
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
@page "/auth/register"
|
||||||
|
@inject IJSRuntime JSRuntime
|
||||||
|
|
||||||
|
<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="layout-container flex h-full grow flex-col">
|
||||||
|
<div class="flex flex-1 justify-center py-5 md:px-40">
|
||||||
|
<div class="layout-content-container flex flex-col w-full max-w-[480px] py-5 flex-1">
|
||||||
|
|
||||||
|
<h2 class="text-text-title tracking-light text-[28px] font-bold leading-tight px-4 text-center pb-3 pt-5">
|
||||||
|
회원가입
|
||||||
|
</h2>
|
||||||
|
<p class="text-red-600 font-normal text-xs text-right px-4">* 는 필수 사항입니다.</p>
|
||||||
|
|
||||||
|
<div class="flex w-full flex-wrap items-end gap-4 px-4 py-3">
|
||||||
|
<label class="flex flex-col w-full">
|
||||||
|
<p class="text-text-title text-base font-medium leading-normal pb-2">
|
||||||
|
이름
|
||||||
|
<span class="text-red-600">*</span>
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
pattern="\d{16}"
|
||||||
|
maxlength="16"
|
||||||
|
placeholder="실명을 입력해주세요. 최대 16글자"
|
||||||
|
class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-xl text-text-title focus:outline-0 focus:ring-0 border border-[#dde0e3] bg-white focus:border-[#dde0e3] h-14 placeholder:text-[#6a7581] p-[15px] text-base font-normal leading-normal"
|
||||||
|
@bind-value="@name"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex w-full flex-wrap items-end gap-4 px-4 py-3">
|
||||||
|
<label class="flex flex-col w-full">
|
||||||
|
<p class="text-text-title text-base font-medium leading-normal pb-2">생일</p>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
@ref="dateInputRef"
|
||||||
|
placeholder="YYYYMMDD"
|
||||||
|
class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-xl text-text-title focus:outline-0 focus:ring-0 border border-[#dde0e3] bg-white focus:border-[#dde0e3] h-14 placeholder:text-[#6a7581] p-[15px] text-base font-normal leading-normal"
|
||||||
|
@bind-value="birth"
|
||||||
|
@onclick="OpenDatePicker"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex w-full flex-wrap items-end gap-4 px-4 py-3">
|
||||||
|
<label class="flex flex-col w-full">
|
||||||
|
<p class="text-text-title text-base font-medium leading-normal pb-2">E-Mail
|
||||||
|
<span class="text-red-600">*</span>
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
placeholder="Enter your email"
|
||||||
|
class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-xl text-text-title focus:outline-0 focus:ring-0 border border-[#dde0e3] bg-white focus:border-[#dde0e3] h-14 placeholder:text-[#6a7581] p-[15px] text-base font-normal leading-normal"
|
||||||
|
@bind-value="email"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex w-full flex-wrap items-end gap-4 px-4 py-3">
|
||||||
|
<label class="flex flex-col w-full">
|
||||||
|
<p class="text-text-title text-base font-medium leading-normal pb-2">전화번호</p>
|
||||||
|
<div class="flex w-full max-w-[480px] items-center gap-2">
|
||||||
|
<input
|
||||||
|
maxlength="3"
|
||||||
|
pattern="\d{3}"
|
||||||
|
placeholder="010"
|
||||||
|
class="form-input flex-1 min-w-0 h-12 text-center rounded-xl border border-[#dde0e3] bg-white focus:border-[#dde0e3] placeholder:text-[#6a7581] p-[15px] text-base font-normal leading-normal"
|
||||||
|
@bind-value="phonePart1"
|
||||||
|
inputmode="numeric"
|
||||||
|
autocomplete="off"
|
||||||
|
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
|
||||||
|
/>
|
||||||
|
<span class="self-center">-</span>
|
||||||
|
<input
|
||||||
|
maxlength="4"
|
||||||
|
pattern="\d{4}"
|
||||||
|
placeholder="1234"
|
||||||
|
class="form-input flex-1 min-w-0 h-12 text-center rounded-xl border border-[#dde0e3] bg-white focus:border-[#dde0e3] placeholder:text-[#6a7581] p-[15px] text-base font-normal leading-normal"
|
||||||
|
@bind-value="phonePart2"
|
||||||
|
inputmode="numeric"
|
||||||
|
autocomplete="off"
|
||||||
|
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
|
||||||
|
/>
|
||||||
|
<span class="self-center">-</span>
|
||||||
|
<input
|
||||||
|
maxlength="4"
|
||||||
|
pattern="\d{4}"
|
||||||
|
placeholder="5678"
|
||||||
|
class="form-input flex-1 min-w-0 h-12 text-center rounded-xl border border-[#dde0e3] bg-white focus:border-[#dde0e3] placeholder:text-[#6a7581] p-[15px] text-base font-normal leading-normal"
|
||||||
|
@bind-value="phonePart3"
|
||||||
|
inputmode="numeric"
|
||||||
|
autocomplete="off"
|
||||||
|
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col w-full gap-4 px-4 py-3">
|
||||||
|
<label class="flex flex-col w-full text-text-title text-base font-medium leading-normal">
|
||||||
|
주소
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
placeholder="눌러서 주소를 선택하세요."
|
||||||
|
class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-xl text-text-title focus:outline-0 focus:ring-0 border border-[#dde0e3] bg-white focus:border-[#dde0e3] h-12 placeholder:text-[#6a7581] p-[12px] text-base font-normal leading-normal"
|
||||||
|
@onclick="OnClickAddress"
|
||||||
|
@bind-value="address"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
@if (address != "")
|
||||||
|
{
|
||||||
|
<input
|
||||||
|
placeholder="상세주소를 입력하세요."
|
||||||
|
class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-xl text-text-title focus:outline-0 focus:ring-0 border border-[#dde0e3] bg-white focus:border-[#dde0e3] h-12 placeholder:text-[#6a7581] p-[12px] text-base font-normal leading-normal"
|
||||||
|
@bind-value="detailAddress"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex px-4 py-3">
|
||||||
|
<button
|
||||||
|
@onclick="ConfirmData"
|
||||||
|
class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-xl h-10 px-4 flex-1 bg-second-normal hover:bg-second-dark text-white text-sm font-bold leading-normal tracking-[0.015em]">
|
||||||
|
<span class="truncate">회원가입</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
260
Program/Views/Project/Register.razor.cs
Normal file
260
Program/Views/Project/Register.razor.cs
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using Front.Program.Layout;
|
||||||
|
|
||||||
|
namespace Front.Program.Views.Project;
|
||||||
|
|
||||||
|
public partial class Register : ComponentBase
|
||||||
|
{
|
||||||
|
[Inject] IJSRuntime JS { get; set; }
|
||||||
|
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||||
|
[Inject] private HttpClient Http { get; set; } = default!;
|
||||||
|
[Inject] private IConfiguration Configuration { get; set; } = default!;
|
||||||
|
|
||||||
|
private ElementReference dateInputRef;
|
||||||
|
|
||||||
|
private string name = "";
|
||||||
|
private DateTime? birth;
|
||||||
|
private string email = "";
|
||||||
|
private string phone = "";
|
||||||
|
private string address = "";
|
||||||
|
private string detailAddress = "";
|
||||||
|
private string snsId = "";
|
||||||
|
|
||||||
|
private string phonePart1 = "";
|
||||||
|
private string phonePart2 = "";
|
||||||
|
private string phonePart3 = "";
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
objRef = DotNetObjectReference.Create(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 쿠키에서 토큰 가져오기
|
||||||
|
var token = await JS.InvokeAsync<string>("eval", "document.cookie.split('; ').find(row => row.startsWith('Web_AM_Connect_Key='))?.split('=')[1]");
|
||||||
|
if (string.IsNullOrEmpty(token))
|
||||||
|
{
|
||||||
|
await JS.InvokeVoidAsync("alert", "인증 정보가 없습니다.");
|
||||||
|
NavigationManager.NavigateTo("/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppController를 통해 세션에서 snsId 가져오기
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/in/app/session/get?key=snsId");
|
||||||
|
request.Headers.Add("Web_AM_Connect_Key", token);
|
||||||
|
|
||||||
|
var response = await Http.SendAsync(request);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var content = await response.Content.ReadFromJsonAsync<JsonElement>();
|
||||||
|
Console.WriteLine($"세션 응답: {content}");
|
||||||
|
|
||||||
|
if (content.TryGetProperty("status", out var statusElement) &&
|
||||||
|
statusElement.TryGetProperty("code", out var codeElement) &&
|
||||||
|
codeElement.GetString() == "000")
|
||||||
|
{
|
||||||
|
if (content.TryGetProperty("data", out var dataElement) &&
|
||||||
|
dataElement.TryGetProperty("data", out var snsIdElement))
|
||||||
|
{
|
||||||
|
snsId = snsIdElement.GetString() ?? "";
|
||||||
|
Console.WriteLine($"서버 세션에서 가져온 SNS ID: {snsId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"세션 데이터 가져오기 실패: {content}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"세션 API 호출 실패: {response.StatusCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(snsId))
|
||||||
|
{
|
||||||
|
Console.WriteLine("SNS ID가 없습니다.");
|
||||||
|
await JS.InvokeVoidAsync("alert", "잘못된 접근입니다.");
|
||||||
|
NavigationManager.NavigateTo("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"SNS ID 가져오기 실패: {ex.Message}");
|
||||||
|
await JS.InvokeVoidAsync("alert", "세션 정보를 가져오는데 실패했습니다.");
|
||||||
|
NavigationManager.NavigateTo("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ConfirmData()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
|
await JS.InvokeVoidAsync("alert", "이름을 입력해주세요.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(email))
|
||||||
|
{
|
||||||
|
await JS.InvokeVoidAsync("alert", "이메일을 입력해주세요.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 전화번호 조합
|
||||||
|
if (phonePart1.Length == 3 && phonePart2.Length == 4 && phonePart3.Length == 4)
|
||||||
|
{
|
||||||
|
phone = $"{phonePart1}-{phonePart2}-{phonePart3}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await JS.InvokeVoidAsync("alert", "전화번호를 올바르게 입력해주세요.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var registerData = new
|
||||||
|
{
|
||||||
|
name = name,
|
||||||
|
birth = birth,
|
||||||
|
email = email,
|
||||||
|
phone = phone,
|
||||||
|
address = address,
|
||||||
|
sns_id = snsId,
|
||||||
|
sns_type = "ST01",
|
||||||
|
type = "UT05",
|
||||||
|
device_id = "",
|
||||||
|
auto_login_yn = false,
|
||||||
|
login_date = DateTime.Now,
|
||||||
|
push_token = "",
|
||||||
|
location_yn = false,
|
||||||
|
camera_yn = false,
|
||||||
|
photo_yn = false,
|
||||||
|
push_yn = false,
|
||||||
|
market_app_yn = false,
|
||||||
|
market_sms_yn = false,
|
||||||
|
market_email_yn = false
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MainLayout.ShowLoading();
|
||||||
|
// 쿠키에서 토큰 가져오기
|
||||||
|
var token = await JS.InvokeAsync<string>("eval", "document.cookie.split('; ').find(row => row.startsWith('Web_AM_Connect_Key='))?.split('=')[1] || ''");
|
||||||
|
Console.WriteLine($"쿠키에서 가져온 토큰: '{token}'");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(token))
|
||||||
|
{
|
||||||
|
await JS.InvokeVoidAsync("alert", "인증 정보가 없습니다.");
|
||||||
|
NavigationManager.NavigateTo("/");
|
||||||
|
|
||||||
|
MainLayout.HideLoading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/in/user/register");
|
||||||
|
request.Headers.Add("Web_AM_Connect_Key", token);
|
||||||
|
Console.WriteLine($"요청 헤더: {string.Join(", ", request.Headers.Select(h => $"{h.Key}: {string.Join(", ", h.Value)}"))}");
|
||||||
|
|
||||||
|
request.Content = JsonContent.Create(registerData);
|
||||||
|
|
||||||
|
var response = await Http.SendAsync(request);
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
|
||||||
|
var status = result.GetProperty("status");
|
||||||
|
var code = status.GetProperty("code").GetString();
|
||||||
|
var message = status.GetProperty("message").GetString();
|
||||||
|
|
||||||
|
if (code == "000")
|
||||||
|
{
|
||||||
|
var data = result.GetProperty("data");
|
||||||
|
var newToken = data.GetProperty("token").GetString();
|
||||||
|
var refresh = data.GetProperty("refresh").GetString();
|
||||||
|
|
||||||
|
// 서버 세션에 토큰 저장
|
||||||
|
var sessionReq = new HttpRequestMessage(HttpMethod.Post, "/api/v1/in/app/session/set");
|
||||||
|
sessionReq.Headers.Add("Web_AM_Connect_Key", token);
|
||||||
|
sessionReq.Content = JsonContent.Create(new[] {
|
||||||
|
new { key = "token", value = newToken },
|
||||||
|
new { key = "refresh", value = refresh }
|
||||||
|
});
|
||||||
|
var sessionResponse = await Http.SendAsync(sessionReq);
|
||||||
|
|
||||||
|
// 세션 스토리지 정리
|
||||||
|
await JS.InvokeVoidAsync("sessionStorage.removeItem", "snsId");
|
||||||
|
|
||||||
|
MainLayout.HideLoading();
|
||||||
|
await JS.InvokeVoidAsync("alert", "회원가입이 완료되었습니다.");
|
||||||
|
NavigationManager.NavigateTo("/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MainLayout.HideLoading();
|
||||||
|
await JS.InvokeVoidAsync("alert", $"회원가입 실패: {message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MainLayout.HideLoading();
|
||||||
|
Console.WriteLine($"API 호출 실패: {response.StatusCode}");
|
||||||
|
var errorContent = await response.Content.ReadAsStringAsync();
|
||||||
|
Console.WriteLine($"에러 내용: {errorContent}");
|
||||||
|
await JS.InvokeVoidAsync("alert", "서버 오류가 발생했습니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MainLayout.HideLoading();
|
||||||
|
Console.WriteLine($"예외 발생: {ex.Message}");
|
||||||
|
await JS.InvokeVoidAsync("alert", $"오류가 발생했습니다: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SubmitPhone()
|
||||||
|
{
|
||||||
|
if (phonePart1.Length == 3 && phonePart2.Length == 4 && phonePart3.Length == 4)
|
||||||
|
{
|
||||||
|
var fullPhone = $"{phonePart1}-{phonePart2}-{phonePart3}";
|
||||||
|
Console.WriteLine($"입력된 전화번호: {fullPhone}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("전화번호를 올바르게 입력해주세요.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenDatePicker()
|
||||||
|
{
|
||||||
|
if (birth == null) birth = DateTime.Now;
|
||||||
|
await JS.InvokeVoidAsync("openDatePicker", dateInputRef);
|
||||||
|
}
|
||||||
|
private void OnBirthChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"선택된 생일: {birth}");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private DotNetObjectReference<Register> objRef;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
objRef = DotNetObjectReference.Create(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task OnClickAddress()
|
||||||
|
{
|
||||||
|
await JS.InvokeVoidAsync("openKakaoPostcodePopup", objRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JSInvokable]
|
||||||
|
public void SetAddress(string roadAddress, string jibunAddress, string zonecode)
|
||||||
|
{
|
||||||
|
address = roadAddress;
|
||||||
|
Console.WriteLine($"SetAddress 호출됨: {roadAddress}, {jibunAddress}, {zonecode}");
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,17 +7,16 @@
|
||||||
<div class="hidden md:flex flex-1 justify-end 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 flex-1 justify-end gap-8">
|
||||||
<div class="flex items-center gap-9">
|
<div class="flex items-center gap-9">
|
||||||
<a class="text-text-title font-medium leading-normal hover:text-blue-800" href="/about" @onclick="() => isOpen = !isOpen">About</a>
|
<a class="text-text-title font-medium leading-normal hover:text-blue-600" href="/about" @onclick="() => isOpen = !isOpen">About</a>
|
||||||
<a class="text-text-title font-medium leading-normal hover:text-blue-800" href="/join" @onclick="() => isOpen = !isOpen">Join</a>
|
<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-800" href="/new" @onclick="() => isOpen = !isOpen">What's New</a>
|
<a class="text-text-title font-medium leading-normal hover:text-blue-600" href="/new" @onclick="() => isOpen = !isOpen">What's New</a>
|
||||||
</div>
|
</div>
|
||||||
<button class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-blue-500 hover:bg-blue-800 text-white text-sm font-bold leading-normal tracking-[0.015em] mr-4"
|
<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">
|
@onclick="OnClickLogin">
|
||||||
<span class="truncate">Get Started</span>
|
<span class="truncate">시작하기</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<button class="md:hidden mr-4" @onclick="OnClickMenuDown">
|
<button class="md:hidden mr-4" @onclick="OnClickMenuDown">
|
||||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
@ -29,13 +28,13 @@
|
||||||
@if (isOpen)
|
@if (isOpen)
|
||||||
{
|
{
|
||||||
<div class="md:hidden absolute top-16 left-0 w-full bg-white shadow z-50 transition-all duration-300">
|
<div class="md:hidden absolute top-16 left-0 w-full bg-white shadow z-50 transition-all duration-300">
|
||||||
<div class="flex flex-col items-start gap-4 p-4">
|
<div class="flex flex-col items-start gap-4 p-4 text-center">
|
||||||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-800" 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="/about" @onclick="() => isOpen = !isOpen">About</a>
|
||||||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-800" 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="/join" @onclick="() => isOpen = !isOpen">Join</a>
|
||||||
<a class="block w-full gap-y-2 text-text-title font-medium leading-normal hover:text-blue-800" href="/new" @onclick="() => isOpen = !isOpen">What's New</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>
|
||||||
<button class="flex w-full cursor-pointer items-center justify-center rounded-lg h-10 px-4 bg-blue-500 hover:bg-blue-800 text-white text-sm font-bold leading-normal tracking-[0.015em]"
|
<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">
|
@onclick="OnClickLogin">
|
||||||
<span class="truncate">Get Started</span>
|
<span class="truncate">시작하기</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -32,6 +32,12 @@
|
||||||
<button class="ml-4 text-red-600 font-bold dismiss">✕</button>
|
<button class="ml-4 text-red-600 font-bold dismiss">✕</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="scripts/scroll.js"></script>
|
||||||
|
<script src="scripts/apiSender.js"></script>
|
||||||
|
<script src="scripts/jsCommonFunc.js"></script>
|
||||||
|
<script src="scripts/kakao-postcode.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<!-- Blazor WASM 로딩 스크립트 -->
|
<!-- Blazor WASM 로딩 스크립트 -->
|
||||||
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
|
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
|
||||||
|
|
||||||
|
@ -69,5 +75,9 @@
|
||||||
document.cookie = name + '=; Max-Age=-99999999;';
|
document.cookie = name + '=; Max-Age=-99999999;';
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
39
wwwroot/kakao-postcode.html
Normal file
39
wwwroot/kakao-postcode.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>주소검색</title>
|
||||||
|
<script src="https://spi.maps.daum.net/imap/map_js_init/postcode.v2.js"></script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
var layer = document.getElementById('layer');
|
||||||
|
new daum.Postcode({
|
||||||
|
oncomplete: function(data) {
|
||||||
|
var jibunAddress = data.jibunAddress || data.autoJibunAddress || "";
|
||||||
|
var postData = {
|
||||||
|
roadAddress: data.roadAddress,
|
||||||
|
jibunAddress: jibunAddress,
|
||||||
|
zonecode: data.zonecode,
|
||||||
|
};
|
||||||
|
window.opener.postMessage({
|
||||||
|
roadAddress: data.roadAddress,
|
||||||
|
jibunAddress: data.jibunAddress,
|
||||||
|
zonecode: data.zonecode
|
||||||
|
}, window.location.origin);
|
||||||
|
window.close();
|
||||||
|
},
|
||||||
|
width: "100%",
|
||||||
|
height: "100%"
|
||||||
|
}).embed(layer);
|
||||||
|
layer.style.display = "block";
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
html, body { margin:0; padding:0; width:100vw; height:100vh; background:#fff; }
|
||||||
|
#layer { width:100vw; height:100vh; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="layer"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
23
wwwroot/scripts/apiSender.js
Normal file
23
wwwroot/scripts/apiSender.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
window.postWithHeader = function(url, method, headerKey, headerValue) {
|
||||||
|
fetch(url, {
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
[headerKey] : headerValue
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
if (res.redirected) {
|
||||||
|
window.location.href = res.url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
window.fetchWithHeaderAndReturnUrl = async function(url, method, headerKey, headerValue) {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
[headerKey]: headerValue
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
return data.url;
|
||||||
|
};
|
8
wwwroot/scripts/jsCommonFunc.js
Normal file
8
wwwroot/scripts/jsCommonFunc.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
window.openDatePicker = function (element) {
|
||||||
|
if (element) {
|
||||||
|
const wasReadOnly = element.readOnly;
|
||||||
|
if (wasReadOnly) element.readOnly = false;
|
||||||
|
element.showPicker();
|
||||||
|
if (wasReadOnly) setTimeout(() => element.readOnly = true, 0);
|
||||||
|
}
|
||||||
|
};
|
28
wwwroot/scripts/kakao-postcode.js
Normal file
28
wwwroot/scripts/kakao-postcode.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
window.addEventListener("message", function (event) {
|
||||||
|
if (event.origin !== window.location.origin) return;
|
||||||
|
if (event.data && event.data.roadAddress) {
|
||||||
|
if (window.kakaoPostcodeDotNetRef) {
|
||||||
|
window.kakaoPostcodeDotNetRef.invokeMethodAsync(
|
||||||
|
"SetAddress",
|
||||||
|
event.data.roadAddress,
|
||||||
|
event.data.jibunAddress,
|
||||||
|
event.data.zonecode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.getKakaoPostcodeResult = function () {
|
||||||
|
return window.kakaoPostcodeResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.openKakaoPostcodePopup = function (dotNetObjRef) {
|
||||||
|
window.kakaoPostcodeResult = null;
|
||||||
|
window.kakaoPostcodeDotNetRef = dotNetObjRef;
|
||||||
|
window.open(
|
||||||
|
"/kakao-postcode.html",
|
||||||
|
"kakaoPostcodePopup",
|
||||||
|
"width=500,height=600,scrollbars=no,resizable=no"
|
||||||
|
);
|
||||||
|
};
|
3
wwwroot/scripts/scroll.js
Normal file
3
wwwroot/scripts/scroll.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
window.scrollToDown = function (y = 0, behavior = "smooth") {
|
||||||
|
window.scrollTo({ top: y, behavior: behavior });
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user