diff --git a/TaxBaik.Web/Components/Admin/App.razor b/TaxBaik.Web/Components/Admin/App.razor index cc1d43d..a646458 100644 --- a/TaxBaik.Web/Components/Admin/App.razor +++ b/TaxBaik.Web/Components/Admin/App.razor @@ -38,6 +38,7 @@ + diff --git a/TaxBaik.Web/Components/Admin/Pages/Login.razor b/TaxBaik.Web/Components/Admin/Pages/Login.razor index e05b920..632dc80 100644 --- a/TaxBaik.Web/Components/Admin/Pages/Login.razor +++ b/TaxBaik.Web/Components/Admin/Pages/Login.razor @@ -12,23 +12,23 @@ 관리자 로그인 - - +
+ name="username" + value="@model.Username" /> + name="password" />
- +
@@ -39,12 +39,12 @@ style="width: 100%; min-height: 52px; border: 0; border-radius: 4px; color: white;"> 로그인 - +
@code { - private LoginModel model = new(); + private readonly LoginModel model = new(); private const string RememberedUsernameKey = "admin-remembered-username"; protected override async Task OnInitializedAsync() @@ -69,42 +69,10 @@ await Js.InvokeVoidAsync("taxbaikAdminSession.syncRouteClass"); } - private async Task HandleLogin() - { - var request = new { model.Username, model.Password }; - var response = await ApiClient.PostAsync("auth/login", request); - - if (response?.AccessToken == null || response?.RefreshToken == null) - { - return; - } - - if (model.RememberMe) - { - await LocalStorageService.SetItemAsStringAsync(RememberedUsernameKey, model.Username); - } - else - { - await LocalStorageService.RemoveItemAsync(RememberedUsernameKey); - } - - await Js.InvokeVoidAsync("localStorage.setItem", "accessToken", response.AccessToken); - await Js.InvokeVoidAsync("localStorage.setItem", "refreshToken", response.RefreshToken); - await Js.InvokeVoidAsync("localStorage.setItem", "tokenExpiry", DateTimeOffset.UtcNow.AddSeconds(response.ExpiresIn).ToUnixTimeMilliseconds().ToString()); - await Js.InvokeVoidAsync("window.location.assign", "/taxbaik/admin/dashboard"); - } - private class LoginModel { public string Username { get; set; } = ""; public string Password { get; set; } = ""; public bool RememberMe { get; set; } } - - private class LoginResponse - { - public string AccessToken { get; set; } = ""; - public string RefreshToken { get; set; } = ""; - public int ExpiresIn { get; set; } - } } diff --git a/TaxBaik.Web/wwwroot/js/admin-session.js b/TaxBaik.Web/wwwroot/js/admin-session.js index 154ddf9..7e558a0 100644 --- a/TaxBaik.Web/wwwroot/js/admin-session.js +++ b/TaxBaik.Web/wwwroot/js/admin-session.js @@ -110,6 +110,61 @@ window.taxbaikAdminSession = { new MutationObserver(reloadOnRejectedCircuit) .observe(modal, { attributes: true, attributeFilter: ['class'] }); + }, + + bindLoginForm: function () { + const form = document.getElementById('admin-login-form'); + if (!form || form.dataset.bound === '1') return; + + form.dataset.bound = '1'; + form.addEventListener('submit', async function (event) { + event.preventDefault(); + + const username = form.querySelector('input[placeholder="사용자명"]')?.value?.trim() || ''; + const password = form.querySelector('input[placeholder="비밀번호"]')?.value || ''; + const rememberMe = form.querySelector('input[type="checkbox"]')?.checked || false; + const existing = form.parentElement.querySelector('.login-error-message'); + const submitButton = form.querySelector('button[type="submit"]'); + + if (existing) existing.remove(); + if (submitButton) submitButton.disabled = true; + + try { + const response = await fetch('/taxbaik/api/auth/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username, password }) + }); + + if (!response.ok) { + throw new Error('login failed'); + } + + const data = await response.json(); + if (!data?.accessToken || !data?.refreshToken) { + throw new Error('invalid response'); + } + + localStorage.setItem('accessToken', data.accessToken); + localStorage.setItem('refreshToken', data.refreshToken); + localStorage.setItem('tokenExpiry', String(Date.now() + (data.expiresIn || 3600) * 1000)); + + if (rememberMe) { + localStorage.setItem('admin-remembered-username', username); + } else { + localStorage.removeItem('admin-remembered-username'); + } + + window.location.href = '/taxbaik/admin/dashboard'; + } catch { + const error = document.createElement('div'); + error.className = 'mud-alert mud-alert-filled-error login-error-message mb-4'; + error.textContent = '로그인 중 오류가 발생했습니다.'; + form.parentElement.insertBefore(error, form); + } finally { + if (submitButton) submitButton.disabled = false; + } + }); } };