Merge pull request 'main' (#20) from seonkyu.kim/AcaMate_Web:main into debug
All checks were successful
AcaMate_FO/pipeline/head This commit looks good
All checks were successful
AcaMate_FO/pipeline/head This commit looks good
Reviewed-on: https://git.ipstein.myds.me/AcaMate/AcaMate_Web/pulls/20
This commit is contained in:
commit
6bb994d2dc
|
@ -31,6 +31,9 @@ builder.Services.AddScoped(sp => //new HttpClient
|
|||
// SCOPED 으로 등록된 서비스는 DI 컨테이너에 등록된 서비스의 인스턴스를 사용합니다.
|
||||
builder.Services.AddScoped<APIService>();
|
||||
builder.Services.AddScoped<CookieService>();
|
||||
// builder.Services.AddRazorPages();
|
||||
// builder.Services.AddServerSideBlazor();
|
||||
builder.Services.AddScoped<LoadingService>();
|
||||
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
|
|
|
@ -1,31 +1,14 @@
|
|||
@* @inherits LayoutComponentBase *@
|
||||
@* *@
|
||||
@* *@
|
||||
@* <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
|
||||
@inherits LayoutComponentBase
|
||||
@implements IDisposable
|
||||
|
||||
<div class="min-h-screen flex flex-col bg-gray-50 text-gray-900">
|
||||
|
||||
<!-- Top 영역 -->
|
||||
@* <TopBanner /> *@
|
||||
@if (!isHideTop)
|
||||
{
|
||||
<TopNav />
|
||||
}
|
||||
|
||||
<!-- 본문 영역 -->
|
||||
<div class="flex flex-1 flex-col md:flex-row">
|
||||
|
@ -48,4 +31,13 @@
|
|||
<!-- 하단 메뉴 -->
|
||||
<BottomNav />
|
||||
<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>
|
||||
|
|
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">
|
||||
<h1 class="text-2xl font-bold mb-4">로그인</h1>
|
||||
<div class="w-full max-w-xs">
|
||||
<input type="text" placeholder="아이디" class="mb-4 p-2 border border-gray-300 rounded w-full" />
|
||||
<input type="password" placeholder="비밀번호" class="mb-4 p-2 border border-gray-300 rounded w-full" />
|
||||
<button @onclick = "KakaoLogin" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 w-full">로그인</button>
|
||||
<button type="button" class="w-full mb-4 p-2 rounded focus:outline-none" @onclick="KakaoLogin">
|
||||
<img src="//k.kakaocdn.net/14/dn/btqCn0WEmI3/nijroPfbpCa4at5EIsjyf0/o.jpg"
|
||||
alt="카카오 로그인"
|
||||
class="rounded w-full transition duration-150 hover:brightness-90" />
|
||||
</button>
|
||||
</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.JSInterop;
|
||||
|
||||
|
@ -6,11 +9,21 @@ namespace Front.Program.Views.Project;
|
|||
public partial class Auth : ComponentBase
|
||||
{
|
||||
[Inject] NavigationManager NavigationManager { get; set; } = default!;
|
||||
[Inject] IJSRuntime JS { get; set; } = default!;
|
||||
void KakaoLogin()
|
||||
[Inject] LoadingService LoadingService { get; set; } = default!;
|
||||
// [Inject] IJSRuntime JS { get; set; } = default!;
|
||||
// [Inject] CookieService Cookie { get; set; } = default!;
|
||||
[Inject] HttpClient Http { get; set; } = default!;
|
||||
|
||||
public async Task KakaoLogin()
|
||||
{
|
||||
// await JS
|
||||
// Redirect to Kakao login page
|
||||
NavigationManager.NavigateTo("/api/v1/in/user/kakao/auth", true);
|
||||
LoadingService.ShowLoading();
|
||||
var url = "/api/v1/out/user/kakao/auth";
|
||||
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,18 +7,17 @@
|
|||
<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-800" 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-800" href="/new" @onclick="() => isOpen = !isOpen">What's New</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-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>
|
||||
<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">
|
||||
<span class="truncate">Get Started</span>
|
||||
<span class="truncate">시작하기</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button class="md:hidden mr-4" @onclick="OnClickMenuDown">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
|
@ -29,13 +28,13 @@
|
|||
@if (isOpen)
|
||||
{
|
||||
<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">
|
||||
<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-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-800" 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]"
|
||||
<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-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>
|
||||
<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">
|
||||
<span class="truncate">Get Started</span>
|
||||
<span class="truncate">시작하기</span>
|
||||
</button>
|
||||
</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>
|
||||
</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 로딩 스크립트 -->
|
||||
<script src="_framework/blazor.webassembly.js" autostart="false"></script>
|
||||
|
||||
|
@ -69,5 +75,9 @@
|
|||
document.cookie = name + '=; Max-Age=-99999999;';
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</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