diff --git a/MoneyMap/Pages/Transactions.cshtml b/MoneyMap/Pages/Transactions.cshtml
index ba9d51c..e1b2a7d 100644
--- a/MoneyMap/Pages/Transactions.cshtml
+++ b/MoneyMap/Pages/Transactions.cshtml
@@ -122,6 +122,17 @@
+
+@if (Model.CategoryBreakdowns.Any())
+{
+
+}
+
@if (Model.Transactions.Any())
{
@@ -304,6 +315,31 @@ else
}
@section Scripts {
+
+
}
diff --git a/MoneyMap/Pages/Transactions.cshtml.cs b/MoneyMap/Pages/Transactions.cshtml.cs
index 6b954e7..3c7edfb 100644
--- a/MoneyMap/Pages/Transactions.cshtml.cs
+++ b/MoneyMap/Pages/Transactions.cshtml.cs
@@ -50,6 +50,7 @@ namespace MoneyMap.Pages
public List AvailableMerchants { get; set; } = new();
public List AvailableCards { get; set; } = new();
public TransactionStats Stats { get; set; } = new();
+ public List CategoryBreakdowns { get; set; } = new();
public async Task OnGetAsync()
{
@@ -61,15 +62,16 @@ namespace MoneyMap.Pages
.Include(t => t.Merchant)
.AsQueryable();
- // Apply filters
+ // Apply filters (case-insensitive search using EF.Functions.Like)
if (!string.IsNullOrWhiteSpace(Search))
{
+ var searchPattern = $"%{Search}%";
query = query.Where(t =>
- t.Name.Contains(Search) ||
- (t.Memo != null && t.Memo.Contains(Search)) ||
- (t.Category != null && t.Category.Contains(Search)) ||
- (t.Notes != null && t.Notes.Contains(Search)) ||
- (t.Merchant != null && t.Merchant.Name.Contains(Search)));
+ EF.Functions.Like(t.Name, searchPattern) ||
+ (t.Memo != null && EF.Functions.Like(t.Memo, searchPattern)) ||
+ (t.Category != null && EF.Functions.Like(t.Category, searchPattern)) ||
+ (t.Notes != null && EF.Functions.Like(t.Notes, searchPattern)) ||
+ (t.Merchant != null && EF.Functions.Like(t.Merchant.Name, searchPattern)));
}
if (!string.IsNullOrWhiteSpace(Category))
@@ -154,6 +156,21 @@ namespace MoneyMap.Pages
// Calculate stats for filtered results (all pages, not just current)
Stats = await _statsService.CalculateStatsAsync(query);
+ // Calculate category breakdown for pie chart (only expenses)
+ var expenseQuery = query.Where(t => t.Amount < 0).ExcludeTransfers();
+ var categoryGroups = await expenseQuery
+ .GroupBy(t => t.Category ?? "")
+ .Select(g => new CategoryBreakdown
+ {
+ Category = g.Key,
+ TotalSpend = g.Sum(x => -x.Amount),
+ Count = g.Count()
+ })
+ .OrderByDescending(x => x.TotalSpend)
+ .ToListAsync();
+
+ CategoryBreakdowns = categoryGroups;
+
// Get available categories for filter dropdown
AvailableCategories = await _referenceDataService.GetAvailableCategoriesAsync();
@@ -178,5 +195,12 @@ namespace MoneyMap.Pages
public string AccountLabel { get; set; } = "";
public int ReceiptCount { get; set; }
}
+
+ public class CategoryBreakdown
+ {
+ public string Category { get; set; } = "";
+ public decimal TotalSpend { get; set; }
+ public int Count { get; set; }
+ }
}
}
\ No newline at end of file