using System.Globalization; using Duempelkas.App.Services.Models; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; namespace Duempelkas.App.Pages; public partial class Dashboard { #region Fields private List? accounts; private bool showAddAccount; private bool showEditClubName; private bool showRestoreConfirm; private bool showYearFilterDialog; private int? selectedYear = DateTime.Now.Year; private List availableYears = []; private string clubName = string.Empty; private string? operationMessage; private string operationMessageClass = "alert-info"; private string? savedPdfPath; private string currentTheme = "light"; #endregion #region Properties private string DisplayClubName => string.IsNullOrWhiteSpace(clubName) ? "Mein Verein" : clubName; private decimal TotalClubBalance => accounts?.Sum(a => a.TotalBalance) ?? 0m; #endregion #region Lifecycle protected override async Task OnInitializedAsync() { await LoadClubName(); await LoadAll(); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) { return; } try { currentTheme = await JS.InvokeAsync("duempelkasThemeGetCurrentTheme"); } catch (JSException) { // Keep default light mode when JS interop is not ready or unavailable. currentTheme = "light"; } StateHasChanged(); } #endregion #region Data Loading private async Task LoadAll() { await LoadAccounts(); availableYears = await EntryService.GetAllEntryYearsAsync(); } private async Task LoadAccounts() { accounts = await AccountService.GetAllAccountsAsync(selectedYear); } private async Task LoadClubName() { clubName = await SettingsService.GetClubNameAsync() ?? string.Empty; } #endregion #region Actions private async Task HandleAccountCreated(string name) { await AccountService.CreateAccountAsync(name); showAddAccount = false; await LoadAll(); } private async Task HandleSaveClubName(string newName) { await SettingsService.SetClubNameAsync(newName); showEditClubName = false; await LoadClubName(); } private async Task HandleBackupAsync() { var message = await BackupService.CreateBackupAsync(); if (message.Contains("fehlgeschlagen", StringComparison.OrdinalIgnoreCase)) { SetOperationMessage(message, false); } } private Task HandleRestoreAsync() { showRestoreConfirm = true; return Task.CompletedTask; } private void CancelRestoreConfirm() { showRestoreConfirm = false; } private async Task HandleConfirmRestore() { showRestoreConfirm = false; var message = await BackupService.RestoreBackupAsync(); var isSuccess = message.StartsWith("Wiederherstellung erfolgreich", StringComparison.OrdinalIgnoreCase); if (isSuccess) { NavigationManager.NavigateTo("/", forceLoad: true); } else { SetOperationMessage(message, isSuccess); } } private async Task HandleDashboardExportAsync() { var pdf = await PdfStatementService.GenerateDashboardStatementAsync(selectedYear); var suffix = selectedYear.HasValue ? $"_{selectedYear.Value}" : "_Gesamt"; savedPdfPath = await FileSaveService.SaveFileAsync(pdf, $"{DisplayClubName}_Übersicht{suffix}.pdf"); } private void OpenYearFilterDialog() { showYearFilterDialog = true; } private void CloseYearFilterDialog() { showYearFilterDialog = false; } private async Task SelectFilterYear(int? year) { selectedYear = year; showYearFilterDialog = false; await LoadAll(); } private async Task HandleOpenSavedPdf() { if (!string.IsNullOrWhiteSpace(savedPdfPath)) { await FileSaveService.OpenFileAsync(savedPdfPath); } savedPdfPath = null; } private void CancelOpenSavedPdf() { savedPdfPath = null; } #endregion #region Helpers private void SetOperationMessage(string message, bool success) { operationMessage = message; operationMessageClass = success ? "alert-success" : "alert-danger"; } private static string FormatCurrency(decimal amount) { return amount.ToString("N2", CultureInfo.GetCultureInfo("de-DE")) + " €"; } private string GetFilterLabel() => selectedYear?.ToString() ?? "Alle"; private string ThemeButtonLabel => currentTheme == "dark" ? "Hell" : "Dunkel"; private string ThemeButtonIconClass => currentTheme == "dark" ? "bi bi-sun" : "bi bi-moon-stars"; private async Task ToggleThemeAsync() { try { currentTheme = await JS.InvokeAsync("duempelkasThemeToggleTheme"); } catch (JSException) { currentTheme = currentTheme == "dark" ? "light" : "dark"; } } [Inject] private IJSRuntime JS { get; set; } = default!; #endregion }