WIP
This commit is contained in:
1 parent
67a2bd527a
commit
8313d8e85a
9 files changed
+122
-7
No files matched your search
@@ -7,7 +7,7 @@
|
||||
|
||||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">💰 Budgeteer</a>
|
||||
<a class="navbar-brand" href="">💰 Budgeteer <span class="badge bg-warning text-dark" style="font-size: 0.55em; vertical-align: middle;">beta</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
@layout AuthLayout
|
||||
@inject IConfiguration Configuration
|
||||
|
||||
<PageTitle>Budgeteer — About</PageTitle>
|
||||
<PageTitle>Budgeteer Beta — About</PageTitle>
|
||||
|
||||
<h3 class="text-center mb-4">💰 Budgeteer</h3>
|
||||
<h3 class="text-center mb-4">💰 Budgeteer <span class="badge bg-warning text-dark" style="font-size: 0.55em; vertical-align: middle;">beta</span></h3>
|
||||
|
||||
<p class="text-center text-muted mb-4">
|
||||
A personal finance dashboard built with Blazor Server.
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
<p>The <a href="/settings">Settings</a> page provides account management options:</p>
|
||||
<ul>
|
||||
<li><strong>Change password</strong> — Enter your current password and choose a new one.</li>
|
||||
<li><strong>Reset data</strong> — Wipe all your accounts, transactions and categories to start fresh. Your login credentials are kept.</li>
|
||||
<li><strong>Delete account</strong> — Permanently removes your user account and all associated data. This action cannot be undone.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -6,9 +6,13 @@
|
||||
@inject NavigationManager Navigation
|
||||
@inject IAuthenticationSchemeProvider SchemeProvider
|
||||
|
||||
<PageTitle>Budgeteer — Sign In</PageTitle>
|
||||
<PageTitle>Budgeteer Beta — Sign In</PageTitle>
|
||||
|
||||
<h3 class="text-center mb-4">Sign In</h3>
|
||||
<div class="text-center mb-4">
|
||||
<span style="font-size: 3rem;">💰</span>
|
||||
<h2 class="mt-2 mb-0 fw-bold">Budgeteer <span class="badge bg-warning text-dark" style="font-size: 0.45em; vertical-align: middle;">beta</span></h2>
|
||||
<p class="text-muted">Sign in to your account</p>
|
||||
</div>
|
||||
|
||||
<EditForm Model="Model" OnValidSubmit="HandleLogin" FormName="login">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<PageTitle>Budgeteer — Register</PageTitle>
|
||||
<PageTitle>Budgeteer Beta — Register</PageTitle>
|
||||
|
||||
<h3 class="text-center mb-4">Create Account</h3>
|
||||
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
@inject AuthenticationStateProvider AuthStateProvider
|
||||
@inject ApplicationDbContext DbContext
|
||||
@inject NavigationManager Navigation
|
||||
@inject AppState AppState
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Settings</PageTitle>
|
||||
|
||||
<h3 class="mb-4">Settings</h3>
|
||||
<h3 class="mb-4">
|
||||
Settings
|
||||
<span class="badge bg-warning text-dark ms-2" style="font-size: 0.4em; vertical-align: middle;">beta</span>
|
||||
</h3>
|
||||
|
||||
@* ── Change Password ── *@
|
||||
<div class="card mb-4">
|
||||
@@ -52,6 +56,49 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* ── Reset Data ── *@
|
||||
<div class="card mb-4 border-warning">
|
||||
<div class="card-header bg-warning">
|
||||
<h5 class="mb-0">Reset Data</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="fw-semibold">
|
||||
This will permanently delete all your accounts, transactions and categories, giving you a clean slate. Your user account and password will be kept.
|
||||
</p>
|
||||
|
||||
@if (resetSuccess)
|
||||
{
|
||||
<div class="alert alert-success">All data has been reset successfully.</div>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(resetError))
|
||||
{
|
||||
<div class="alert alert-danger">@resetError</div>
|
||||
}
|
||||
|
||||
@if (!confirmingReset)
|
||||
{
|
||||
<button class="btn btn-outline-warning" @onclick="() => confirmingReset = true">
|
||||
Reset All Data
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-warning">
|
||||
<strong>Are you sure?</strong> This cannot be undone. Type <code>I UNDERSTAND</code> and enter your password to confirm.
|
||||
</div>
|
||||
<div class="mb-3" style="max-width: 400px;">
|
||||
<input type="text" class="form-control mb-2" placeholder="Type I UNDERSTAND to confirm" @bind="resetConfirmation" />
|
||||
<input type="password" class="form-control mb-2" placeholder="Enter your password" @bind="resetPassword" />
|
||||
<div class="d-flex gap-2">
|
||||
<button class="btn btn-warning" @onclick="ResetData">Confirm Reset</button>
|
||||
<button class="btn btn-secondary" @onclick="CancelReset">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* ── Delete Account ── *@
|
||||
<div class="card border-danger">
|
||||
<div class="card-header bg-danger text-white">
|
||||
@@ -88,6 +135,9 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private static readonly string appVersion =
|
||||
typeof(Program).Assembly.GetName().Version?.ToString(3) ?? "0.0.0";
|
||||
|
||||
private ChangePasswordForm passwordForm = new();
|
||||
private bool passwordSuccess;
|
||||
private string? passwordError;
|
||||
@@ -96,6 +146,12 @@
|
||||
private string deletePassword = string.Empty;
|
||||
private string? deleteError;
|
||||
|
||||
private bool confirmingReset;
|
||||
private string resetConfirmation = string.Empty;
|
||||
private string resetPassword = string.Empty;
|
||||
private string? resetError;
|
||||
private bool resetSuccess;
|
||||
|
||||
private async Task ChangePassword()
|
||||
{
|
||||
passwordSuccess = false;
|
||||
@@ -166,6 +222,59 @@
|
||||
deleteError = null;
|
||||
}
|
||||
|
||||
private async Task ResetData()
|
||||
{
|
||||
resetError = null;
|
||||
resetSuccess = false;
|
||||
|
||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||
var userIdClaim = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
|
||||
if (userIdClaim is null) return;
|
||||
|
||||
var user = await UserManager.FindByIdAsync(userIdClaim);
|
||||
if (user is null) return;
|
||||
|
||||
if (!string.Equals(resetConfirmation?.Trim(), "I UNDERSTAND", StringComparison.Ordinal))
|
||||
{
|
||||
resetError = "Please type 'I UNDERSTAND' exactly to confirm.";
|
||||
return;
|
||||
}
|
||||
|
||||
var passwordValid = await UserManager.CheckPasswordAsync(user, resetPassword);
|
||||
if (!passwordValid)
|
||||
{
|
||||
resetError = "Incorrect password.";
|
||||
return;
|
||||
}
|
||||
|
||||
await DbContext.Transactions
|
||||
.Where(t => t.Account.UserId == userIdClaim)
|
||||
.ExecuteDeleteAsync();
|
||||
|
||||
await DbContext.Accounts
|
||||
.Where(a => a.UserId == userIdClaim)
|
||||
.ExecuteDeleteAsync();
|
||||
|
||||
await DbContext.Categories
|
||||
.Where(c => c.UserId == userIdClaim)
|
||||
.ExecuteDeleteAsync();
|
||||
|
||||
confirmingReset = false;
|
||||
resetConfirmation = string.Empty;
|
||||
resetPassword = string.Empty;
|
||||
resetSuccess = true;
|
||||
|
||||
AppState.NotifyAccountsChanged();
|
||||
}
|
||||
|
||||
private void CancelReset()
|
||||
{
|
||||
confirmingReset = false;
|
||||
resetConfirmation = string.Empty;
|
||||
resetPassword = string.Empty;
|
||||
resetError = null;
|
||||
}
|
||||
|
||||
private sealed class ChangePasswordForm
|
||||
{
|
||||
[System.ComponentModel.DataAnnotations.Required(ErrorMessage = "Current password is required")]
|
||||
|
||||
Reference in new issue
Block a user