Files
Budgeteer/BudgetApp/Services/DashboardService.cs
T
2026-03-01 19:00:23 +00:00

148 lines
5.5 KiB
C#

using BudgetApp.Data;
namespace BudgetApp.Services;
public class DashboardService(TransactionService transactionService, AccountService accountService, CategoryService categoryService)
{
private readonly TransactionService _transactionService = transactionService;
private readonly AccountService _accountService = accountService;
private readonly CategoryService _categoryService = categoryService;
public async Task<DashboardData> GetDashboardDataAsync(string userId, DateTime? from = null, DateTime? to = null)
{
await _categoryService.EnsureDefaultCategoriesAsync(userId);
var windowEnd = to ?? DateTime.Today.AddDays(30);
await _transactionService.MaterializeRecurringTransactionsAsync(userId, windowEnd);
var accounts = await _accountService.GetAccountsAsync(userId);
var categories = await _categoryService.GetCategoriesAsync(userId);
var windowStart = from ?? DateTime.Today.AddDays(-30);
var fetchStart = windowStart < DateTime.Today ? windowStart : DateTime.Today;
var fetchEnd = windowEnd > DateTime.Today ? windowEnd : DateTime.Today;
var allTransactions = await _transactionService.GetTransactionsInRangeAsync(userId, fetchStart, fetchEnd);
var recent = allTransactions
.Where(t => t.Date.Date >= windowStart.Date && t.Date.Date <= DateTime.Today)
.OrderByDescending(t => t.Date)
.ToList();
var upcoming = allTransactions
.Where(t => t.Date.Date > DateTime.Today && t.Date.Date <= windowEnd.Date)
.OrderBy(t => t.Date)
.ToList();
var chartData = BuildChartData(accounts, allTransactions, windowStart, windowEnd);
return new DashboardData
{
Accounts = accounts,
Categories = categories,
RecentTransactions = recent,
UpcomingTransactions = upcoming,
ChartData = chartData,
CurrencySymbol = accounts.FirstOrDefault()?.GetSymbol() ?? "£"
};
}
internal static ChartData BuildChartData(List<Account> accounts, List<Transaction> transactions, DateTime startDate, DateTime endDate)
{
var today = DateTime.Today;
var labels = new List<string>();
var datasets = new List<ChartDataset>();
var dayTransactionLabels = new List<List<string>>();
for (var d = startDate; d <= endDate; d = d.AddDays(1))
{
labels.Add(d.ToString("MMM dd"));
var dayTxns = transactions
.Where(t => t.Date.Date == d.Date)
.Select(t => $"{(t.Type == TransactionType.Income ? "+" : "-")}{t.Account.FormatAmount(t.Amount)} {t.Description} ({t.Account.Name})")
.ToList();
dayTransactionLabels.Add(dayTxns);
}
foreach (var account in accounts)
{
var accountTransactions = transactions
.Where(t => t.AccountId == account.Id)
.OrderBy(t => t.Date)
.ToList();
var dataPoints = new List<decimal>();
var runningBalance = account.CurrentBalance;
if (startDate.Date <= today)
{
foreach (var t in accountTransactions
.Where(t => t.Date.Date >= startDate.Date && t.Date.Date <= today)
.OrderByDescending(t => t.Date))
{
runningBalance -= t.Type == TransactionType.Income ? t.Amount : -t.Amount;
}
}
else
{
foreach (var t in accountTransactions
.Where(t => t.Date.Date > today && t.Date.Date < startDate.Date)
.OrderBy(t => t.Date))
{
runningBalance += t.Type == TransactionType.Income ? t.Amount : -t.Amount;
}
}
for (var d = startDate; d <= endDate; d = d.AddDays(1))
{
var dayTxns = accountTransactions.Where(t => t.Date.Date == d.Date);
foreach (var t in dayTxns)
{
runningBalance += t.Type == TransactionType.Income ? t.Amount : -t.Amount;
}
dataPoints.Add(runningBalance);
}
datasets.Add(new ChartDataset
{
Label = account.Name,
Color = account.Color,
Data = dataPoints,
CurrencySymbol = account.GetSymbol()
});
}
return new ChartData
{
Labels = labels,
Datasets = datasets,
DayTransactionLabels = dayTransactionLabels
};
}
}
public class DashboardData
{
public List<Account> Accounts { get; set; } = [];
public List<Category> Categories { get; set; } = [];
public List<Transaction> RecentTransactions { get; set; } = [];
public List<Transaction> UpcomingTransactions { get; set; } = [];
public ChartData ChartData { get; set; } = new();
public string CurrencySymbol { get; set; } = "$";
}
public class ChartData
{
public List<string> Labels { get; set; } = [];
public List<ChartDataset> Datasets { get; set; } = [];
public List<List<string>> DayTransactionLabels { get; set; } = [];
}
public class ChartDataset
{
public string Label { get; set; } = string.Empty;
public string Color { get; set; } = "#1b6ec2";
public List<decimal> Data { get; set; } = [];
public string CurrencySymbol { get; set; } = "$";
}