AuthorBuddy/Components/Pages/Login.razor

166 lines
4.6 KiB
Text
Raw Normal View History

2026-05-21 11:04:42 +02:00
@page "/login"
@inject IAuthService AuthService
@inject CustomAuthStateProvider AuthStateProvider
@inject NavigationManager Navigation
@inject ISettingsService SettingsService
2026-05-25 06:38:16 +02:00
@inject ILocalizationService Loc
2026-05-21 11:04:42 +02:00
@rendermode InteractiveServer
2026-05-25 06:38:16 +02:00
<PageTitle>@Loc["page.title.login"]</PageTitle>
2026-05-21 11:04:42 +02:00
<div class="auth-page">
<div class="auth-card">
2026-05-25 06:38:16 +02:00
<div class="auth-logo">
<img src="/Assets/logo.jpg" alt="Author Buddy" />
</div>
<h2>@Loc["login.heading"]</h2>
2026-05-21 11:04:42 +02:00
@if (!show2FA)
{
<div class="form-group">
2026-05-25 06:38:16 +02:00
<label for="username">@Loc["login.label.username"]</label>
2026-05-21 11:04:42 +02:00
<input id="username" @bind="username" @onkeydown="HandleKeyDown" />
</div>
<div class="form-group">
2026-05-25 06:38:16 +02:00
<label for="password">@Loc["login.label.password"]</label>
2026-05-21 11:04:42 +02:00
<input id="password" type="password" @bind="password" @onkeydown="HandleKeyDown" />
</div>
<div class="auth-actions">
2026-05-25 06:38:16 +02:00
<button @onclick="DoLogin" disabled="@isBusy">@Loc["login.button.submit"]</button>
<a href="/register">@Loc["login.link.register"]</a>
2026-05-21 11:04:42 +02:00
</div>
}
else
{
2026-05-25 06:38:16 +02:00
<p>@Loc["login.2fa.instruction"]</p>
2026-05-21 11:04:42 +02:00
<div class="form-group">
2026-05-25 06:38:16 +02:00
<label for="code">@Loc["login.2fa.label.code"]</label>
2026-05-21 11:04:42 +02:00
<input id="code" @bind="twoFactorCode" maxlength="6" @onkeydown="HandleKeyDown" />
</div>
<div class="auth-actions">
2026-05-25 06:38:16 +02:00
<button @onclick="Verify2FA" disabled="@isBusy">@Loc["login.2fa.button.verify"]</button>
2026-05-21 11:04:42 +02:00
</div>
}
@if (!string.IsNullOrEmpty(errorMessage))
{
<div class="auth-error">@errorMessage</div>
}
</div>
</div>
@code {
private string username = string.Empty;
private string password = string.Empty;
private string twoFactorCode = string.Empty;
private string errorMessage = string.Empty;
private bool isBusy;
private bool show2FA;
protected override async Task OnInitializedAsync()
{
if (AuthService.IsLoggedIn)
{
Navigation.NavigateTo("/");
return;
}
var users = await SettingsService.GetUsersAsync();
if (users.Count == 0)
{
Navigation.NavigateTo("/register");
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && AuthService.IsLoggedIn)
Navigation.NavigateTo("/");
}
private async Task HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
if (show2FA)
await Verify2FA();
else
await DoLogin();
}
}
private async Task DoLogin()
{
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
{
2026-05-25 06:38:16 +02:00
errorMessage = Loc["login.error.empty_fields"];
2026-05-21 11:04:42 +02:00
return;
}
isBusy = true;
errorMessage = string.Empty;
try
{
var result = await AuthService.LoginAsync(username, password);
if (AuthService.Is2FARequired)
{
show2FA = true;
password = string.Empty;
}
else if (result)
{
AuthStateProvider.NotifyStateChanged();
Navigation.NavigateTo("/");
}
else
{
2026-05-25 06:38:16 +02:00
errorMessage = Loc["login.error.invalid_credentials"];
2026-05-21 11:04:42 +02:00
}
}
catch (Exception ex)
{
2026-05-25 06:38:16 +02:00
errorMessage = $"{Loc["common.error"]} {ex.Message}";
2026-05-21 11:04:42 +02:00
}
finally
{
isBusy = false;
}
}
private async Task Verify2FA()
{
if (string.IsNullOrWhiteSpace(twoFactorCode) || twoFactorCode.Length != 6)
{
2026-05-25 06:38:16 +02:00
errorMessage = Loc["login.2fa.error.invalid_code"];
2026-05-21 11:04:42 +02:00
return;
}
isBusy = true;
errorMessage = string.Empty;
try
{
var result = await AuthService.Verify2FAAsync(twoFactorCode);
if (result)
{
AuthStateProvider.NotifyStateChanged();
Navigation.NavigateTo("/");
}
else
{
2026-05-25 06:38:16 +02:00
errorMessage = Loc["login.2fa.error.code_failed"];
2026-05-21 11:04:42 +02:00
}
}
catch (Exception ex)
{
2026-05-25 06:38:16 +02:00
errorMessage = $"{Loc["common.error"]} {ex.Message}";
2026-05-21 11:04:42 +02:00
}
finally
{
isBusy = false;
}
}
}