WIP
This commit is contained in:
1 parent
38067df8c3
commit
492d86db9e
30 files changed
+2473
-40
No files matched your search
@@ -3,6 +3,7 @@
|
||||
@inject TransactionService TransactionService
|
||||
@inject AccountService AccountService
|
||||
@inject CategoryService CategoryService
|
||||
@inject SalaryService SalaryService
|
||||
@inject AuthenticationStateProvider AuthStateProvider
|
||||
@rendermode InteractiveServer
|
||||
|
||||
@@ -176,11 +177,28 @@ else
|
||||
@foreach (var t in pagedTransactions)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<input type="checkbox" class="form-check-input" checked="@selectedIds.Contains(t.Id)" @onchange="() => ToggleSelect(t.Id)" />
|
||||
</td>
|
||||
<td>
|
||||
@if (t.SalaryId is null)
|
||||
{
|
||||
<input type="checkbox" class="form-check-input" checked="@selectedIds.Contains(t.Id)" @onchange="() => ToggleSelect(t.Id)" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-muted" style="font-size: 0.85rem;" title="Salary transactions cannot be bulk deleted — manage them on the Salary page">🔒</span>
|
||||
}
|
||||
</td>
|
||||
<td class="text-nowrap">@t.Date.ToString("MMM dd, yyyy")</td>
|
||||
<td>@t.Description</td>
|
||||
<td>
|
||||
@t.Description
|
||||
@if (t.SalaryId is not null)
|
||||
{
|
||||
<span class="badge bg-primary ms-1" style="font-size: 0.7rem;">💰 Salary</span>
|
||||
}
|
||||
@if (t.IsPaid && t.Date.Date > DateTime.Today)
|
||||
{
|
||||
<span class="badge bg-success ms-1" style="font-size: 0.7rem;">✓ Paid</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge" style="background-color: @t.Account.Color;">
|
||||
@t.Account.Name
|
||||
@@ -215,8 +233,21 @@ else
|
||||
</td>
|
||||
<td class="text-end text-nowrap">
|
||||
<div class="btn-group btn-group-sm">
|
||||
@if (t.Date.Date > DateTime.Today)
|
||||
{
|
||||
<button class="btn @(t.IsPaid ? "btn-success" : "btn-outline-success")"
|
||||
title="@(t.IsPaid ? "Mark as unpaid" : "Mark as paid")"
|
||||
@onclick="() => TogglePaid(t)">✓</button>
|
||||
}
|
||||
<button class="btn btn-outline-primary" @onclick="() => OpenEditModal(t)">Edit</button>
|
||||
<button class="btn btn-outline-danger" @onclick="() => ConfirmDelete(t)">Delete</button>
|
||||
@if (t.SalaryId is null)
|
||||
{
|
||||
<button class="btn btn-outline-danger" @onclick="() => ConfirmDelete(t)">Delete</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a href="/salary" class="btn btn-outline-secondary" title="Salary transactions are managed on the Salary page">🔒</a>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -448,18 +479,20 @@ else
|
||||
|
||||
private void OnSearchChanged() => currentPage = 1;
|
||||
|
||||
private void SetWindow(int days)
|
||||
private async Task SetWindow(int days)
|
||||
{
|
||||
windowPreset = days switch { 7 => "7d", 30 => "30d", 90 => "90d", 365 => "1y", _ => null };
|
||||
windowStart = DateTime.Today;
|
||||
windowEnd = DateTime.Today.AddDays(days);
|
||||
currentPage = 1;
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private void OnWindowDateChanged()
|
||||
private async Task OnWindowDateChanged()
|
||||
{
|
||||
windowPreset = null;
|
||||
currentPage = 1;
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private void OnPageSizeChanged(ChangeEventArgs e)
|
||||
@@ -501,6 +534,7 @@ else
|
||||
{
|
||||
if (userId is null) return;
|
||||
|
||||
await SalaryService.MaterializeSalaryTransactionsAsync(userId, windowEnd);
|
||||
transactions = await TransactionService.GetTransactionsAsync(userId);
|
||||
accountsList = await AccountService.GetAccountsAsync(userId);
|
||||
categoriesList = await CategoryService.GetCategoriesAsync(userId);
|
||||
@@ -539,22 +573,29 @@ else
|
||||
|
||||
private void ToggleSelect(int id)
|
||||
{
|
||||
var t = transactions?.FirstOrDefault(x => x.Id == id);
|
||||
if (t?.SalaryId is not null) return;
|
||||
if (!selectedIds.Remove(id))
|
||||
selectedIds.Add(id);
|
||||
}
|
||||
|
||||
private bool IsAllPageSelected() => pagedTransactions.Count > 0 && pagedTransactions.All(t => selectedIds.Contains(t.Id));
|
||||
private bool IsAllPageSelected()
|
||||
{
|
||||
var selectable = pagedTransactions.Where(t => t.SalaryId is null).ToList();
|
||||
return selectable.Count > 0 && selectable.All(t => selectedIds.Contains(t.Id));
|
||||
}
|
||||
|
||||
private void ToggleSelectAll(ChangeEventArgs e)
|
||||
{
|
||||
var selectable = pagedTransactions.Where(t => t.SalaryId is null).ToList();
|
||||
if (e.Value is true)
|
||||
{
|
||||
foreach (var t in pagedTransactions)
|
||||
foreach (var t in selectable)
|
||||
selectedIds.Add(t.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var t in pagedTransactions)
|
||||
foreach (var t in selectable)
|
||||
selectedIds.Remove(t.Id);
|
||||
}
|
||||
}
|
||||
@@ -649,8 +690,10 @@ else
|
||||
{
|
||||
if (userId is null) return;
|
||||
showDeleteModal = false;
|
||||
foreach (var id in selectedIds)
|
||||
foreach (var id in selectedIds.ToList())
|
||||
{
|
||||
var t = transactions?.FirstOrDefault(x => x.Id == id);
|
||||
if (t?.SalaryId is not null) continue;
|
||||
await TransactionService.DeleteTransactionAsync(id, userId);
|
||||
}
|
||||
selectedIds.Clear();
|
||||
@@ -664,6 +707,13 @@ else
|
||||
bulkDeleteCount = 0;
|
||||
}
|
||||
|
||||
private async Task TogglePaid(Transaction t)
|
||||
{
|
||||
if (userId is null) return;
|
||||
await TransactionService.MarkAsPaidAsync(t.Id, userId, !t.IsPaid);
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private sealed class TransactionForm : System.ComponentModel.DataAnnotations.IValidatableObject
|
||||
{
|
||||
[System.ComponentModel.DataAnnotations.Required(ErrorMessage = "Description is required")]
|
||||
|
||||
Reference in new issue
Block a user