This commit is contained in:
rossmill76 committed 2026-03-02 15:28:54 +00:00
1 parent 45a5e3fc5e
commit 67a2bd527a
13 files changed
+220 -32

No files matched your search

+6 -6
View File
@@ -19,15 +19,15 @@
<div class="row g-3 align-items-end">
<div class="col-md-3">
<label class="form-label">Account Name</label>
<InputText @bind-Value="formModel.Name" class="form-control" placeholder="e.g. Current Account" />
<InputText @bind-Value="formModel.Name" class="form-control" placeholder="e.g. Current Account" title="A friendly name for this account" />
</div>
<div class="col-md-2">
<label class="form-label">Current Balance</label>
<InputNumber @bind-Value="formModel.CurrentBalance" class="form-control numeric-input" />
<InputNumber @bind-Value="formModel.CurrentBalance" class="form-control numeric-input" title="The opening balance for this account" />
</div>
<div class="col-md-2">
<label class="form-label">Currency</label>
<InputSelect @bind-Value="formModel.CurrencyCode" class="form-select">
<InputSelect @bind-Value="formModel.CurrencyCode" class="form-select" title="Currency used for this account">
@foreach (var kvp in Account.CurrencySymbols)
{
<option value="@kvp.Key">@kvp.Key (@kvp.Value)</option>
@@ -36,7 +36,7 @@
</div>
<div class="col-md-2">
<label class="form-label">Colour</label>
<InputText @bind-Value="formModel.Color" type="color" class="form-control form-control-color" />
<InputText @bind-Value="formModel.Color" type="color" class="form-control form-control-color" title="Colour used to identify this account in charts and lists" />
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">Add</button>
@@ -94,8 +94,8 @@ else
<small class="text-muted">@account.CurrencyCode</small>
</div>
<div class="d-flex gap-1">
<button class="btn btn-outline-primary btn-sm" @onclick="() => StartAccountEdit(account)">Edit</button>
<button class="btn btn-outline-danger btn-sm" @onclick="() => ConfirmDeleteAccount(account)">Delete</button>
<button class="btn btn-outline-primary btn-sm" title="Edit account name, currency or colour" @onclick="() => StartAccountEdit(account)">Edit</button>
<button class="btn btn-outline-danger btn-sm" title="Delete this account and all its transactions" @onclick="() => ConfirmDeleteAccount(account)">Delete</button>
</div>
</div>
Whitespace-only changes.
+4 -4
View File
@@ -18,12 +18,12 @@
<div class="row g-3 align-items-end">
<div class="col-md-6">
<label class="form-label">Category Name</label>
<InputText @bind-Value="formModel.Name" class="form-control" placeholder="e.g. Groceries, Rent, Salary" />
<InputText @bind-Value="formModel.Name" class="form-control" placeholder="e.g. Groceries, Rent, Salary" title="A name to group related transactions" />
</div>
<div class="col-md-2">
<label class="form-label">Icon</label>
<button type="button" class="btn btn-outline-secondary w-100" style="font-size: 1.4rem; height: 38px; padding: 0;"
@onclick="OpenAddIconPicker">@(string.IsNullOrEmpty(formModel.Icon) ? "📁" : formModel.Icon)</button>
title="Click to choose an emoji icon" @onclick="OpenAddIconPicker">@(string.IsNullOrEmpty(formModel.Icon) ? "📁" : formModel.Icon)</button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-primary w-100">Add</button>
@@ -75,8 +75,8 @@ else
}
else
{
<button class="btn btn-outline-primary btn-sm" @onclick="() => StartCategoryEdit(category)">Edit</button>
<button class="btn btn-outline-danger btn-sm" @onclick="() => DeleteCategory(category.Id)">Delete</button>
<button class="btn btn-outline-primary btn-sm" title="Edit category name or icon" @onclick="() => StartCategoryEdit(category)">Edit</button>
<button class="btn btn-outline-danger btn-sm" title="Delete this category — transactions will become uncategorised" @onclick="() => DeleteCategory(category.Id)">Delete</button>
}
</div>
</div>
+177
View File
@@ -0,0 +1,177 @@
@page "/help"
@attribute [Authorize]
<PageTitle>Help</PageTitle>
<h3 class="mb-4">Help</h3>
<div class="row">
<div class="col-lg-8">
@* ── Getting Started ── *@
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">🚀 Getting Started</h5>
</div>
<div class="card-body">
<p>Welcome to <strong>Budgeteer</strong> — a personal finance dashboard to track your accounts, transactions and spending categories.</p>
<ol class="mb-0">
<li class="mb-2">
<strong>Create an account</strong> — Head to <a href="/accounts">Accounts</a> and add at least one financial account (e.g. "Current Account", "Savings"). Set the opening balance and choose a currency.
</li>
<li class="mb-2">
<strong>Set up categories</strong> — Visit <a href="/categories">Categories</a> to organise your spending. Pick an emoji icon for each category to make them easy to spot.
</li>
<li class="mb-2">
<strong>Record transactions</strong> — Go to <a href="/transactions">Transactions</a> or use the <strong>+ Add</strong> button on the <a href="/">Dashboard</a> to log income and expenses.
</li>
<li>
<strong>Review your dashboard</strong> — The <a href="/">Dashboard</a> shows a balance trend chart and lists your recent and upcoming transactions.
</li>
</ol>
</div>
</div>
@* ── Dashboard ── *@
<div class="card mb-4" id="dashboard">
<div class="card-header">
<h5 class="mb-0">📊 Dashboard</h5>
</div>
<div class="card-body">
<p>The <a href="/">Dashboard</a> is your home screen and gives you an at-a-glance view of your finances.</p>
<h6>Balance Trend Chart</h6>
<p>The chart shows projected balances for each account over a time window starting from today. Use the preset buttons (<strong>7d</strong>, <strong>30d</strong>, <strong>90d</strong>, <strong>1y</strong>) to look ahead, or pick custom dates with the date pickers.</p>
<h6>Recent &amp; Upcoming Tabs</h6>
<ul>
<li><strong>Recent</strong> — Transactions that have already occurred, sorted by most recent first.</li>
<li><strong>Upcoming</strong> — Future transactions (including recurring ones) with projected account balances shown alongside each entry.</li>
</ul>
<h6>Quick Actions</h6>
<ul>
<li><strong>Click a transaction</strong> to expand it and reveal Edit and Delete buttons.</li>
<li>Use the <strong>search box</strong> to filter by description, account, category or amount.</li>
<li>When you have multiple accounts, use the <strong>account filter buttons</strong> below the tabs to show or hide specific accounts.</li>
<li>The <strong>+ Add</strong> button opens a quick-add modal — after saving, the form stays open so you can add multiple transactions in a row.</li>
</ul>
</div>
</div>
@* ── Accounts ── *@
<div class="card mb-4" id="accounts">
<div class="card-header">
<h5 class="mb-0">🏦 Accounts</h5>
</div>
<div class="card-body">
<p>The <a href="/accounts">Accounts</a> page lets you manage your financial accounts.</p>
<ul>
<li><strong>Add an account</strong> — Enter a name, starting balance, currency and colour. The colour is used throughout the app to identify the account.</li>
<li><strong>Edit</strong> — Click the Edit button on any account card to change its name, currency or colour.</li>
<li><strong>Adjust balance</strong> — Click the displayed balance amount to manually correct it.</li>
<li><strong>Delete</strong> — Removes the account and <em>all</em> associated transactions. This cannot be undone.</li>
</ul>
<p class="mb-0">Account balances are also shown in the navigation sidebar — click them to jump to the Accounts page.</p>
</div>
</div>
@* ── Transactions ── *@
<div class="card mb-4" id="transactions">
<div class="card-header">
<h5 class="mb-0">💸 Transactions</h5>
</div>
<div class="card-body">
<p>The <a href="/transactions">Transactions</a> page provides a full sortable and searchable table of all your transactions.</p>
<h6>Adding a Transaction</h6>
<ul>
<li>Fill in the description, amount, date, type (Income or Expense), account and optionally a category.</li>
<li>Amounts are always entered as positive numbers — the type field determines whether it adds to or subtracts from the account balance.</li>
</ul>
<h6>Recurring Transactions</h6>
<ul>
<li>Set a recurrence of <strong>Daily</strong>, <strong>Weekly</strong>, <strong>Monthly</strong> or <strong>Yearly</strong> when creating a transaction.</li>
<li>Optionally set an end date (up to 1 year from the transaction date). If left blank, it defaults to 1 year.</li>
<li>Future occurrences appear in the <strong>Upcoming</strong> tab on the Dashboard.</li>
<li>When editing a recurring transaction, changes apply to that occurrence <em>and all future ones</em> in the series.</li>
<li>When deleting, you can choose to delete just one occurrence or the entire future series.</li>
</ul>
<h6>Sorting &amp; Filtering</h6>
<ul>
<li>Click any column header to sort the table.</li>
<li>Use the search box and account/type/category drop-downs to narrow results.</li>
<li>Select multiple transactions with checkboxes for bulk deletion.</li>
</ul>
</div>
</div>
@* ── Categories ── *@
<div class="card mb-4" id="categories">
<div class="card-header">
<h5 class="mb-0">🏷️ Categories</h5>
</div>
<div class="card-body">
<p>The <a href="/categories">Categories</a> page lets you create and manage spending categories.</p>
<ul>
<li><strong>Add a category</strong> — Enter a name and pick an emoji icon from the icon picker.</li>
<li><strong>Edit</strong> — Click the Edit button on a category card to change its name or icon.</li>
<li><strong>Delete</strong> — Removes the category. Transactions using it will become uncategorised.</li>
</ul>
<p class="mb-0">Categories are optional — you can assign them to transactions to get better insight into your spending patterns.</p>
</div>
</div>
@* ── Settings ── *@
<div class="card mb-4" id="settings">
<div class="card-header">
<h5 class="mb-0">⚙️ Settings</h5>
</div>
<div class="card-body">
<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>Delete account</strong> — Permanently removes your user account and all associated data. This action cannot be undone.</li>
</ul>
</div>
</div>
@* ── Tips ── *@
<div class="card mb-4" id="tips">
<div class="card-header">
<h5 class="mb-0">💡 Tips</h5>
</div>
<div class="card-body">
<ul class="mb-0">
<li>Use the Dashboard <strong>+ Add</strong> button for rapid entry — the modal stays open after each save so you can batch-add transactions.</li>
<li>Set up recurring transactions for regular bills and income to keep your upcoming view accurate.</li>
<li>Assign colours to your accounts to easily distinguish them on the chart and in transaction lists.</li>
<li>Hover over elements for tooltips with additional context throughout the app.</li>
<li>Click your account balances in the sidebar to quickly navigate to account management.</li>
</ul>
</div>
</div>
</div>
@* ── Sidebar quick links ── *@
<div class="col-lg-4">
<div class="card position-sticky" style="top: 1rem;">
<div class="card-header">
<h6 class="mb-0">Quick Navigation</h6>
</div>
<div class="list-group list-group-flush">
<a href="/help#dashboard" class="list-group-item list-group-item-action">📊 Dashboard</a>
<a href="/help#accounts" class="list-group-item list-group-item-action">🏦 Accounts</a>
<a href="/help#transactions" class="list-group-item list-group-item-action">💸 Transactions</a>
<a href="/help#categories" class="list-group-item list-group-item-action">🏷️ Categories</a>
<a href="/help#settings" class="list-group-item list-group-item-action">⚙️ Settings</a>
<a href="/help#tips" class="list-group-item list-group-item-action">💡 Tips</a>
</div>
<div class="card-footer text-center">
<a href="/about" class="text-muted" style="font-size: 0.85rem;">About Budgeteer</a>
</div>
</div>
</div>
</div>
+13 -12
View File
@@ -29,16 +29,16 @@ else
<h5 class="mb-0">Balance Trend</h5>
<div class="d-flex flex-wrap align-items-center gap-2">
<div class="btn-group btn-group-sm">
<button class="btn @(windowPreset == "7d" ? "btn-primary" : "btn-outline-secondary")" @onclick="() => SetWindow(7)">7d</button>
<button class="btn @(windowPreset == "30d" ? "btn-primary" : "btn-outline-secondary")" @onclick="() => SetWindow(30)">30d</button>
<button class="btn @(windowPreset == "90d" ? "btn-primary" : "btn-outline-secondary")" @onclick="() => SetWindow(90)">90d</button>
<button class="btn @(windowPreset == "1y" ? "btn-primary" : "btn-outline-secondary")" @onclick="() => SetWindow(365)">1y</button>
<button class="btn @(windowPreset == "7d" ? "btn-primary" : "btn-outline-secondary")" title="Show next 7 days" @onclick="() => SetWindow(7)">7d</button>
<button class="btn @(windowPreset == "30d" ? "btn-primary" : "btn-outline-secondary")" title="Show next 30 days" @onclick="() => SetWindow(30)">30d</button>
<button class="btn @(windowPreset == "90d" ? "btn-primary" : "btn-outline-secondary")" title="Show next 90 days" @onclick="() => SetWindow(90)">90d</button>
<button class="btn @(windowPreset == "1y" ? "btn-primary" : "btn-outline-secondary")" title="Show next year" @onclick="() => SetWindow(365)">1y</button>
</div>
<input type="date" class="form-control form-control-sm date-picker"
@bind="windowStart" @bind:after="OnWindowDateChanged" />
title="Custom start date" @bind="windowStart" @bind:after="OnWindowDateChanged" />
<span class="text-muted">to</span>
<input type="date" class="form-control form-control-sm date-picker"
@bind="windowEnd" @bind:after="OnWindowDateChanged" />
title="Custom end date" @bind="windowEnd" @bind:after="OnWindowDateChanged" />
</div>
</div>
<div class="card-body">
@@ -140,20 +140,20 @@ else
<div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
<ul class="nav nav-tabs card-header-tabs" style="flex-grow: 0;">
<li class="nav-item">
<button class="nav-link @(activeTab == "recent" ? "active" : "")" @onclick='() => { activeTab = "recent"; recentPage = 1; }'>
<button class="nav-link @(activeTab == "recent" ? "active" : "")" title="Transactions that have already occurred" @onclick='() => { activeTab = "recent"; recentPage = 1; }'>
Recent <span class="badge bg-secondary ms-1">@filteredRecent.Count</span>
</button>
</li>
<li class="nav-item">
<button class="nav-link @(activeTab == "upcoming" ? "active" : "")" @onclick='() => { activeTab = "upcoming"; upcomingPage = 1; }'>
<button class="nav-link @(activeTab == "upcoming" ? "active" : "")" title="Scheduled future transactions" @onclick='() => { activeTab = "upcoming"; upcomingPage = 1; }'>
Upcoming <span class="badge bg-secondary ms-1">@filteredUpcoming.Count</span>
</button>
</li>
</ul>
<div class="d-flex align-items-center gap-2">
<input type="search" class="form-control form-control-sm" style="max-width: 180px;"
placeholder="Search..." @bind="dashboardSearchQuery" @bind:event="oninput" @bind:after="OnDashboardSearchChanged" />
<button class="btn btn-sm btn-primary" @onclick="OpenAddModal">+ Add</button>
title="Filter by description, account, category or amount" placeholder="Search..." @bind="dashboardSearchQuery" @bind:event="oninput" @bind:after="OnDashboardSearchChanged" />
<button class="btn btn-sm btn-primary" title="Quickly add a new transaction" @onclick="OpenAddModal">+ Add</button>
</div>
</div>
@if (data.Accounts.Count > 1)
@@ -164,6 +164,7 @@ else
{
<button class="btn btn-sm px-2 py-0 @(hiddenAccountIds.Contains(a.Id) ? "btn-outline-secondary" : "")"
style="font-size: 0.75rem; @(hiddenAccountIds.Contains(a.Id) ? "opacity: 0.5;" : $"background-color: {a.Color}; color: white;")"
title="@(hiddenAccountIds.Contains(a.Id) ? $"Show {a.Name} transactions" : $"Hide {a.Name} transactions")"
@onclick="() => ToggleAccountFilter(a.Id)">
@a.Name
</button>
@@ -357,7 +358,7 @@ else
private int lastRenderedChartVersion;
// Time window
private DateTime windowStart = DateTime.Today.AddDays(-30);
private DateTime windowStart = DateTime.Today;
private DateTime windowEnd = DateTime.Today.AddDays(30);
private string windowPreset = "30d";
@@ -617,7 +618,7 @@ else
private async Task SetWindow(int days)
{
windowPreset = days switch { 7 => "7d", 30 => "30d", 90 => "90d", 365 => "1y", _ => "custom" };
windowStart = DateTime.Today.AddDays(-days);
windowStart = DateTime.Today;
windowEnd = DateTime.Today.AddDays(days);
await RefreshData();
}
Whitespace-only changes.
Whitespace-only changes.
@@ -28,11 +28,11 @@
<div class="row g-3">
<div class="col-md-4">
<label class="form-label">Description</label>
<InputText @bind-Value="formModel.Description" class="form-control" placeholder="e.g. Food shopping" />
<InputText @bind-Value="formModel.Description" class="form-control" placeholder="e.g. Food shopping" title="A short description of the transaction" />
</div>
<div class="col-md-2">
<label class="form-label">Amount</label>
<InputNumber @bind-Value="formModel.Amount" class="form-control numeric-input" />
<InputNumber @bind-Value="formModel.Amount" class="form-control numeric-input" title="Enter a positive amount — the type determines income or expense" />
</div>
<div class="col-md-2">
<label class="form-label">Date</label>
@@ -72,7 +72,7 @@
</div>
<div class="col-md-2">
<label class="form-label">Recurrence</label>
<InputSelect @bind-Value="formModel.RecurrenceType" class="form-select">
<InputSelect @bind-Value="formModel.RecurrenceType" class="form-select" title="Set a recurring schedule — future occurrences are generated automatically">
<option value="@RecurrenceType.None">None</option>
<option value="@RecurrenceType.Daily">Daily</option>
<option value="@RecurrenceType.Weekly">Weekly</option>
@@ -109,7 +109,7 @@ else
<div class="card">
<div class="card-header d-flex align-items-center gap-2 flex-wrap">
<label class="form-label mb-0 text-nowrap">Account:</label>
<select class="form-select form-select-sm" style="max-width: 200px;" @onchange="OnAccountFilterChanged">
<select class="form-select form-select-sm" style="max-width: 200px;" title="Filter transactions by account" @onchange="OnAccountFilterChanged">
<option value="">All Accounts</option>
@if (accountsList is not null)
{
@@ -120,7 +120,7 @@ else
}
</select>
<input type="search" class="form-control form-control-sm" style="max-width: 220px;"
placeholder="Search..." @bind="searchQuery" @bind:event="oninput" @bind:after="OnSearchChanged" />
title="Search by description, account, category or amount" placeholder="Search..." @bind="searchQuery" @bind:event="oninput" @bind:after="OnSearchChanged" />
<div class="ms-auto d-flex align-items-center gap-2">
<label class="form-label mb-0 text-nowrap">Show:</label>
<select class="form-select form-select-sm" style="max-width: 90px;" @onchange="OnPageSizeChanged">
@@ -136,14 +136,14 @@ else
<thead class="table-light">
<tr>
<th style="width: 2rem;">
<input type="checkbox" class="form-check-input" checked="@IsAllPageSelected()" @onchange="ToggleSelectAll" />
<input type="checkbox" class="form-check-input" title="Select all transactions on this page" checked="@IsAllPageSelected()" @onchange="ToggleSelectAll" />
</th>
<th role="button" class="user-select-none" @onclick='() => SetSort("date")'>Date @SortIndicator("date")</th>
<th role="button" class="user-select-none" @onclick='() => SetSort("description")'>Description @SortIndicator("description")</th>
<th role="button" class="user-select-none" title="Sort by date" @onclick='() => SetSort("date")'>Date @SortIndicator("date")</th>
<th role="button" class="user-select-none" title="Sort by description" @onclick='() => SetSort("description")'>Description @SortIndicator("description")</th>
<th>Account</th>
<th>Category</th>
<th>Recurrence</th>
<th role="button" class="user-select-none text-end" @onclick='() => SetSort("amount")'>Amount @SortIndicator("amount")</th>
<th role="button" class="user-select-none text-end" title="Sort by amount" @onclick='() => SetSort("amount")'>Amount @SortIndicator("amount")</th>
<th></th>
</tr>
</thead>
Whitespace-only changes.