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 { get => Period.Year; set => Period.Year = value; } private List availableYears = []; private string clubName = string.Empty; private string? savedPdfPath; private FileOperationResult? fileResult; private bool fileBusy; 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 = Period.Choices(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(AccountSetup setup) { await AccountService.CreateAccountAsync(setup.Name, setup.InitialBalance); showAddAccount = false; await LoadAll(); } private async Task HandleSaveClubName(string newName) { await SettingsService.SetClubNameAsync(newName); showEditClubName = false; await LoadClubName(); } private async Task HandleBackupAsync() { if (fileBusy) return; var busyToast = Toasts.Show("Dateiaktion läuft … Bitte warten.", persistent: true); fileBusy = true; fileResult = null; try { fileResult = await BackupService.CreateBackupAsync(); } catch (Exception ex) { fileResult = FileOperationResult.Error(ex); } finally { fileBusy = false; Toasts.Dismiss(busyToast); } } private Task HandleRestoreAsync() { showRestoreConfirm = true; return Task.CompletedTask; } private void CancelRestoreConfirm() { showRestoreConfirm = false; } private async Task HandleConfirmRestore() { if (fileBusy) return; var busyToast = Toasts.Show("Dateiaktion läuft … Bitte warten.", persistent: true); fileBusy = true; fileResult = null; try { showRestoreConfirm = false; fileResult = await BackupService.RestoreBackupAsync(); if (fileResult.Status == FileOperationStatus.Success) await LoadAll(); } catch (Exception ex) { fileResult = FileOperationResult.Error(ex); } finally { fileBusy = false; Toasts.Dismiss(busyToast); } } private async Task HandleDashboardExportAsync() { if (fileBusy) return; var busyToast = Toasts.Show("Dateiaktion läuft … Bitte warten.", persistent: true); fileBusy = true; fileResult = null; try { var pdf = await PdfStatementService.GenerateDashboardStatementAsync(selectedYear); var suffix = selectedYear.HasValue ? $"_{selectedYear.Value}" : "_Gesamt"; fileResult = await FileSaveService.SaveFileAsync(pdf, $"{DisplayClubName}_Übersicht{suffix}.pdf"); savedPdfPath = fileResult.Status == FileOperationStatus.Success ? fileResult.Path : null; } catch (Exception ex) { fileResult = FileOperationResult.Error(ex); } finally { fileBusy = false; Toasts.Dismiss(busyToast); } } 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 (fileBusy) return; var busyToast = Toasts.Show("Dateiaktion läuft … Bitte warten.", persistent: true); fileBusy = true; fileResult = null; try { if (!string.IsNullOrWhiteSpace(savedPdfPath)) { fileResult = await FileSaveService.OpenFileAsync(savedPdfPath); } savedPdfPath = null; } catch (Exception ex) { fileResult = FileOperationResult.Error(ex); } finally { fileBusy = false; Toasts.Dismiss(busyToast); } } private void CancelOpenSavedPdf() { savedPdfPath = null; } #endregion #region Helpers private static string FormatCurrency(decimal amount) { return amount.ToString("N2", CultureInfo.GetCultureInfo("de-DE")) + " €"; } private string GetFilterLabel() => Period.Label; 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 }