fix: restore admin login submit handler
TaxBaik CI/CD / build-and-deploy (push) Failing after 1m40s

This commit is contained in:
2026-07-01 14:31:10 +09:00
parent 0f6ba33af3
commit 777cdcd918
3 changed files with 63 additions and 39 deletions
+1
View File
@@ -38,6 +38,7 @@
<script src="_content/MudBlazor/MudBlazor.min.js"></script> <script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script src="js/admin-session.js"></script> <script src="js/admin-session.js"></script>
<script src="_framework/blazor.web.js"></script> <script src="_framework/blazor.web.js"></script>
<script>window.taxbaikAdminSession?.bindLoginForm();</script>
<script>window.taxbaikAdminSession?.watchReconnect();</script> <script>window.taxbaikAdminSession?.watchReconnect();</script>
</body> </body>
</html> </html>
+7 -39
View File
@@ -12,23 +12,23 @@
<MudPaper Class="pa-8" Elevation="3" Style="width: 100%; max-width: 400px;"> <MudPaper Class="pa-8" Elevation="3" Style="width: 100%; max-width: 400px;">
<MudText Typo="Typo.h4" Class="mb-6 text-center">관리자 로그인</MudText> <MudText Typo="Typo.h4" Class="mb-6 text-center">관리자 로그인</MudText>
<EditForm Model="model" OnValidSubmit="HandleLogin"> <form id="admin-login-form">
<DataAnnotationsValidator />
<input class="mud-input mud-input-outlined mud-input-root mud-input-root-adorned-start mb-4" <input class="mud-input mud-input-outlined mud-input-root mud-input-root-adorned-start mb-4"
style="width: 100%; min-height: 56px; padding: 16px 14px;" style="width: 100%; min-height: 56px; padding: 16px 14px;"
placeholder="사용자명" placeholder="사용자명"
autocomplete="username" autocomplete="username"
@bind="model.Username" /> name="username"
value="@model.Username" />
<input type="password" <input type="password"
class="mud-input mud-input-outlined mud-input-root mud-input-root-adorned-start mb-4" class="mud-input mud-input-outlined mud-input-root mud-input-root-adorned-start mb-4"
style="width: 100%; min-height: 56px; padding: 16px 14px;" style="width: 100%; min-height: 56px; padding: 16px 14px;"
placeholder="비밀번호" placeholder="비밀번호"
autocomplete="current-password" autocomplete="current-password"
@bind="model.Password" /> name="password" />
<div class="mb-4"> <div class="mb-4">
<input class="mud-checkbox" type="checkbox" @bind="model.RememberMe" /> <input class="mud-checkbox" type="checkbox" name="rememberMe" />
<label style="margin-left: 8px; cursor: pointer;">아이디 저장</label> <label style="margin-left: 8px; cursor: pointer;">아이디 저장</label>
</div> </div>
@@ -39,12 +39,12 @@
style="width: 100%; min-height: 52px; border: 0; border-radius: 4px; color: white;"> style="width: 100%; min-height: 52px; border: 0; border-radius: 4px; color: white;">
<span>로그인</span> <span>로그인</span>
</button> </button>
</EditForm> </form>
</MudPaper> </MudPaper>
</MudContainer> </MudContainer>
@code { @code {
private LoginModel model = new(); private readonly LoginModel model = new();
private const string RememberedUsernameKey = "admin-remembered-username"; private const string RememberedUsernameKey = "admin-remembered-username";
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
@@ -69,42 +69,10 @@
await Js.InvokeVoidAsync("taxbaikAdminSession.syncRouteClass"); await Js.InvokeVoidAsync("taxbaikAdminSession.syncRouteClass");
} }
private async Task HandleLogin()
{
var request = new { model.Username, model.Password };
var response = await ApiClient.PostAsync<LoginResponse>("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 private class LoginModel
{ {
public string Username { get; set; } = ""; public string Username { get; set; } = "";
public string Password { get; set; } = ""; public string Password { get; set; } = "";
public bool RememberMe { 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; }
}
} }
+55
View File
@@ -110,6 +110,61 @@ window.taxbaikAdminSession = {
new MutationObserver(reloadOnRejectedCircuit) new MutationObserver(reloadOnRejectedCircuit)
.observe(modal, { attributes: true, attributeFilter: ['class'] }); .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;
}
});
} }
}; };