[] 회원가입 동작

1. UI 수정
2. 전화번호 유효성 검사
3. 회원가입 로직 진행
4. 데이터 세션 저장 로직 추가
This commit is contained in:
김선규 2025-06-04 17:53:51 +09:00
parent f3fee47c28
commit 0698f65ddf
3 changed files with 222 additions and 50 deletions

View File

@ -1,16 +1,21 @@
@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 md:justify-center">
<div class="layout-content-container flex flex-col w-[512px] max-w-[480px] py-5 flex-1">
<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>
회원가입
</h2>
<p class="text-red-600 font-normal text-xs text-right px-4">* 는 필수 사항입니다.</p>
<div class="flex max-w-[480px] flex-wrap items-end gap-4 px-4 py-3">
<label class="flex flex-col min-w-40 flex-1">
<p class="text-text-title text-base font-medium leading-normal pb-2">이름
<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
@ -22,8 +27,9 @@
/>
</label>
</div>
<div class="flex max-w-[480px] flex-wrap items-end gap-4 px-4 py-3">
<label class="flex flex-col min-w-40 flex-1">
<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"
@ -36,8 +42,9 @@
/>
</label>
</div>
<div class="flex max-w-[480px] flex-wrap items-end gap-4 px-4 py-3">
<label class="flex flex-col min-w-40 flex-1">
<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>
@ -47,55 +54,49 @@
@bind-value="email"/>
</label>
</div>
<div class="flex max-w-[480px] flex-wrap items-end gap-4 px-4 py-3">
<label class="flex flex-col min-w-40 flex-1">
<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 *@
@* placeholder="(XXX) XXX-XXXX" *@
@* 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="phone" *@
@* /> *@
<div class="flex w-full items-center justify-center gap-2 px-4">
<div class="flex w-full max-w-[480px] items-center gap-2">
<input
maxlength="3"
pattern="\d{3}"
placeholder="010"
class="form-input w-20 h-12 text-center border border-[#dde0e3] rounded-md"
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 w-20 h-12 text-center border border-[#dde0e3] rounded-md"
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 w-20 h-12 text-center border border-[#dde0e3] rounded-md"
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, '')"
/>
<button class="ml-4 h-12 px-6 bg-blue-500 text-white rounded-md font-bold" @onclick="SubmitPhone"
style="min-width: 80px;">
확인
</button>
</div>
</label>
</div>
<div class="flex flex-col max-w-[480px] flex-wrap items-end gap-4 px-4 py-3">
<label class="flex text-left w-full text-text-title text-base font-medium leading-normal">주소
<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="눌러서 주소를 선택하세요."
@ -112,14 +113,13 @@
@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">Register</span>
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>

View File

@ -1,6 +1,9 @@
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;
namespace Front.Program.Views.Project;
@ -8,6 +11,8 @@ 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;
@ -17,12 +22,188 @@ public partial class Register : ComponentBase
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
{
// 쿠키에서 토큰 가져오기
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("/");
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");
await JS.InvokeVoidAsync("alert", "회원가입이 완료되었습니다.");
NavigationManager.NavigateTo("/");
}
else
{
await JS.InvokeVoidAsync("alert", $"회원가입 실패: {message}");
}
}
else
{
Console.WriteLine($"API 호출 실패: {response.StatusCode}");
var errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"에러 내용: {errorContent}");
await JS.InvokeVoidAsync("alert", "서버 오류가 발생했습니다.");
}
}
catch (Exception ex)
{
Console.WriteLine($"예외 발생: {ex.Message}");
await JS.InvokeVoidAsync("alert", $"오류가 발생했습니다: {ex.Message}");
}
}
private void SubmitPhone()
{
if (phonePart1.Length == 3 && phonePart2.Length == 4 && phonePart3.Length == 4)
@ -36,15 +217,6 @@ public partial class Register : ComponentBase
}
}
private void ConfirmData()
{
if (name == "" || phone == "" || address == "" || detailAddress == "")
{
}
Console.WriteLine($"{name} - {birth.ToString()} - {email} - {phone} - {address}");
}
private async Task OpenDatePicker()
{
if (birth == null) birth = DateTime.Now;

File diff suppressed because one or more lines are too long