diff --git a/BudgetApp.Data/Entities/RecurrenceType.cs b/BudgetApp.Data/Entities/RecurrenceType.cs
index 45a7990..b2ae989 100644
--- a/BudgetApp.Data/Entities/RecurrenceType.cs
+++ b/BudgetApp.Data/Entities/RecurrenceType.cs
@@ -6,5 +6,6 @@ public enum RecurrenceType
Daily,
Weekly,
Monthly,
- Yearly
+ Yearly,
+ FourWeekly
}
\ No newline at end of file
diff --git a/BudgetApp.Data/Entities/Salary.cs b/BudgetApp.Data/Entities/Salary.cs
index bb8fca9..7c8e76e 100644
--- a/BudgetApp.Data/Entities/Salary.cs
+++ b/BudgetApp.Data/Entities/Salary.cs
@@ -27,10 +27,11 @@ public class Salary
public string GetPaydaySummary() => RecurrenceType switch
{
- RecurrenceType.Weekly => $"Every week on {StartDate:dddd}",
- RecurrenceType.Monthly => $"Monthly on the {GetOrdinal(StartDate.Day)}",
- RecurrenceType.Yearly => $"Annually on {StartDate:MMMM d}",
- _ => RecurrenceType.ToString()
+ RecurrenceType.Weekly => $"Every week on {StartDate:dddd}",
+ RecurrenceType.FourWeekly => $"Every 4 weeks on {StartDate:dddd}",
+ RecurrenceType.Monthly => $"Monthly on the {GetOrdinal(StartDate.Day)}",
+ RecurrenceType.Yearly => $"Annually on {StartDate:MMMM d}",
+ _ => RecurrenceType.ToString()
};
private static string GetOrdinal(int day) => day switch
diff --git a/BudgetApp.Data/Repositories/SalaryRepository.cs b/BudgetApp.Data/Repositories/SalaryRepository.cs
index eb81fb7..fb4ad33 100644
--- a/BudgetApp.Data/Repositories/SalaryRepository.cs
+++ b/BudgetApp.Data/Repositories/SalaryRepository.cs
@@ -129,9 +129,10 @@ public class SalaryRepository(ApplicationDbContext db) : ISalaryRepository
private static DateTime GetNextDate(DateTime from, Salary salary) => salary.RecurrenceType switch
{
- RecurrenceType.Weekly => from.AddDays(7),
- RecurrenceType.Monthly => from.AddMonths(1),
- RecurrenceType.Yearly => from.AddYears(1),
- _ => from.AddMonths(1)
+ RecurrenceType.Weekly => from.AddDays(7),
+ RecurrenceType.FourWeekly => from.AddDays(28),
+ RecurrenceType.Monthly => from.AddMonths(1),
+ RecurrenceType.Yearly => from.AddYears(1),
+ _ => from.AddMonths(1)
};
}
diff --git a/BudgetApp.Data/Repositories/TransactionRepository.cs b/BudgetApp.Data/Repositories/TransactionRepository.cs
index 01677dc..f653de3 100644
--- a/BudgetApp.Data/Repositories/TransactionRepository.cs
+++ b/BudgetApp.Data/Repositories/TransactionRepository.cs
@@ -278,10 +278,11 @@ public class TransactionRepository(ApplicationDbContext db) : ITransactionReposi
internal static DateTime GetNextOccurrence(DateTime current, RecurrenceType recurrence) => recurrence switch
{
- RecurrenceType.Daily => current.AddDays(1),
- RecurrenceType.Weekly => current.AddDays(7),
- RecurrenceType.Monthly => current.AddMonths(1),
- RecurrenceType.Yearly => current.AddYears(1),
- _ => DateTime.MaxValue
+ RecurrenceType.Daily => current.AddDays(1),
+ RecurrenceType.Weekly => current.AddDays(7),
+ RecurrenceType.FourWeekly => current.AddDays(28),
+ RecurrenceType.Monthly => current.AddMonths(1),
+ RecurrenceType.Yearly => current.AddYears(1),
+ _ => DateTime.MaxValue
};
}
diff --git a/BudgetApp/BudgetApp.csproj b/BudgetApp/BudgetApp.csproj
index c3894b4..850f5c7 100644
--- a/BudgetApp/BudgetApp.csproj
+++ b/BudgetApp/BudgetApp.csproj
@@ -24,4 +24,10 @@
+
+
+ PreserveNewest
+
+
+
diff --git a/BudgetApp/Components/Pages/Home.razor b/BudgetApp/Components/Pages/Home.razor
index 14074b3..44b9a6d 100644
--- a/BudgetApp/Components/Pages/Home.razor
+++ b/BudgetApp/Components/Pages/Home.razor
@@ -110,6 +110,7 @@ else
+
diff --git a/BudgetApp/Components/Pages/Home.razor.cs b/BudgetApp/Components/Pages/Home.razor.cs
index d1cf668..811bb27 100644
--- a/BudgetApp/Components/Pages/Home.razor.cs
+++ b/BudgetApp/Components/Pages/Home.razor.cs
@@ -287,9 +287,14 @@ public partial class Home
private static string GetRecurrenceLabel(Transaction t)
{
- if (t.RecurrenceType != RecurrenceType.None)
- return t.RecurrenceType.ToString();
- return t.ParentTransaction?.RecurrenceType.ToString() ?? "Recurring";
+ var type = t.RecurrenceType != RecurrenceType.None
+ ? t.RecurrenceType
+ : (t.ParentTransaction?.RecurrenceType ?? RecurrenceType.None);
+ return type switch
+ {
+ RecurrenceType.FourWeekly => "4 Weekly",
+ _ => type.ToString()
+ };
}
private void ComputeProjectedBalances()
@@ -342,7 +347,7 @@ public partial class Home
if (_nextPayday is null) return;
var txnsToPayday = await TransactionService.GetTransactionsInRangeAsync(
- _userId, DateTime.Today.AddDays(1), _nextPayday.Value);
+ _userId, DateTime.Today.AddDays(1), _nextPayday.Value.AddDays(-1));
foreach (var account in _data.Accounts)
{
diff --git a/BudgetApp/Components/Pages/Salary.razor b/BudgetApp/Components/Pages/Salary.razor
index d19cef7..85a9116 100644
--- a/BudgetApp/Components/Pages/Salary.razor
+++ b/BudgetApp/Components/Pages/Salary.razor
@@ -51,6 +51,7 @@
+
@@ -192,6 +193,7 @@ else
+
diff --git a/BudgetApp/Components/Pages/Transactions.razor b/BudgetApp/Components/Pages/Transactions.razor
index 45b4d8a..81bdc4b 100644
--- a/BudgetApp/Components/Pages/Transactions.razor
+++ b/BudgetApp/Components/Pages/Transactions.razor
@@ -80,6 +80,7 @@
+
@@ -178,8 +179,15 @@ else
- @foreach (var t in PagedTransactions)
+ @foreach (var group in GroupedPagedTransactions)
{
+
+ |
+ @group.Key.ToString("dddd, d MMMM")
+ |
+
+ @foreach (var t in OrderGroupByIncomeFirst(group))
+ {
OpenEditModal(t)">
|
@if (t.SalaryId is null)
@@ -221,11 +229,11 @@ else
|
@if (t.RecurrenceType != RecurrenceType.None)
{
- 🔁 @t.RecurrenceType
+ 🔁 @GetRecurrenceLabel(t.RecurrenceType)
}
else if (t.ParentTransactionId is not null)
{
- 🔁 @(t.ParentTransaction?.RecurrenceType.ToString() ?? "Recurring")
+ 🔁 @GetRecurrenceLabel(t.ParentTransaction?.RecurrenceType ?? RecurrenceType.None)
}
else
{
@@ -236,7 +244,8 @@ else
@(t.Type == TransactionType.Income ? "+" : "-")@t.Account.FormatAmount(t.Amount)
|
- }
+ }
+ }
diff --git a/BudgetApp/Components/Pages/Transactions.razor.cs b/BudgetApp/Components/Pages/Transactions.razor.cs
index 4b240c8..4e56ed1 100644
--- a/BudgetApp/Components/Pages/Transactions.razor.cs
+++ b/BudgetApp/Components/Pages/Transactions.razor.cs
@@ -26,6 +26,20 @@ public partial class Transactions
.Take(_pageSize)
.ToList();
+ private IEnumerable> GroupedPagedTransactions
+ {
+ get
+ {
+ var groups = PagedTransactions.GroupBy(t => t.Date.Date);
+ return _sortColumn == "date" && _sortAscending
+ ? groups.OrderBy(g => g.Key)
+ : groups.OrderByDescending(g => g.Key);
+ }
+ }
+
+ private static IEnumerable OrderGroupByIncomeFirst(IGrouping group) =>
+ group.OrderByDescending(t => t.Type == TransactionType.Income).ThenBy(t => t.Description);
+
private string _sortColumn = "date";
private bool _sortAscending = true;
@@ -305,6 +319,12 @@ public partial class Transactions
_bulkDeleteCount = 0;
}
+ private static string GetRecurrenceLabel(RecurrenceType type) => type switch
+ {
+ RecurrenceType.FourWeekly => "4 Weekly",
+ _ => type.ToString()
+ };
+
private async Task TogglePaid(Transaction t)
{
if (_userId is null) return;
diff --git a/BudgetApp/budgetapp.db-shm b/BudgetApp/budgetapp.db-shm
index b1ccf5b..7306cb1 100644
Binary files a/BudgetApp/budgetapp.db-shm and b/BudgetApp/budgetapp.db-shm differ
diff --git a/BudgetApp/budgetapp.db-wal b/BudgetApp/budgetapp.db-wal
index 36c7307..4760394 100644
Binary files a/BudgetApp/budgetapp.db-wal and b/BudgetApp/budgetapp.db-wal differ
diff --git a/BudgetApp/budgetapp.db.db b/BudgetApp/budgetapp.db.db
new file mode 100644
index 0000000..bcde87d
Binary files /dev/null and b/BudgetApp/budgetapp.db.db differ