using Duempelkas.App.Services.Models; using Microsoft.AspNetCore.Components; namespace Duempelkas.App.Components.Dialogs; public partial class AddTransferDialog { #region Parameters [Parameter] public int SourceAccountId { get; set; } [Parameter] public EntryDto? EditEntry { get; set; } [Parameter] public EventCallback OnSave { get; set; } [Parameter] public EventCallback OnCancel { get; set; } #endregion [Parameter] public int? ContextYear { get; set; } private bool confirmDifferentYear; private int? confirmedYear; private bool OutsideYear => ContextYear.HasValue && date.Year != ContextYear.Value; private bool isSaving; private bool completed; private BookingSaved? committedResult; private string? saveError; private string? saveDetails; #region Fields private List accounts = new(); private int targetAccountId; private string dateText = DateTime.Today.ToString("yyyy-MM-dd"); private DateTime date => Duempelkas.App.Services.BookingInput.Date(dateText); private string title = string.Empty; private string amountText = string.Empty; private bool ValidAmount => Duempelkas.App.Services.BookingInput.TryAmount(amountText, out _); private decimal amount => Duempelkas.App.Services.BookingInput.TryAmount(amountText, out var value) ? value : 0; private string initialState = string.Empty; private string CurrentState => $"{dateText}|{title}|{amountText}|{targetAccountId}"; private bool IsDirty => CurrentState != initialState; private bool initialized; private int? initializedEntryId; #endregion #region Properties private bool IsIncoming => EditEntry?.Type == Duempelkas.Domain.Enums.EntryType.Income; private string CurrentAccountName => accounts.FirstOrDefault(a => a.Id == SourceAccountId)?.Name ?? "Aktuelles Konto"; private string LinkedAccountName => accounts.FirstOrDefault(a => a.Id == targetAccountId)?.Name ?? "Konto auswählen"; private string FromName => IsIncoming ? LinkedAccountName : CurrentAccountName; private string ToName => IsIncoming ? CurrentAccountName : LinkedAccountName; private static string Money(decimal value) => value.ToString("N2", System.Globalization.CultureInfo.GetCultureInfo("de-DE")) + " €"; private bool CanSave => targetAccountId > 0 && targetAccountId != SourceAccountId && !string.IsNullOrWhiteSpace(title) && ValidAmount && date != default && (!OutsideYear || (confirmDifferentYear && confirmedYear == date.Year)); #endregion #region Lifecycle protected override async Task OnParametersSetAsync() { if (!accounts.Any()) { accounts = await AccountService.GetAllAccountsAsync(); } if (initialized && initializedEntryId == EditEntry?.Id) return; initialized = true; initializedEntryId = EditEntry?.Id; if (EditEntry != null) { targetAccountId = EditEntry.LinkedAccountId ?? 0; dateText = EditEntry.Date.ToString("yyyy-MM-dd"); title = EditEntry.Title; amountText = EditEntry.Amount.ToString("0.00", System.Globalization.CultureInfo.GetCultureInfo("de-DE")); } initialState = CurrentState; } #endregion #region Actions private async Task Save() { if (isSaving || completed) return; if (committedResult == null && bookingDate != null) await bookingDate.CommitAsync(); if (isSaving || completed || (committedResult == null && !CanSave)) return; var busyToast = Toasts.Show("Wird gespeichert …", persistent: true); isSaving = true; saveError = null; saveDetails = null; try { if (committedResult == null) { var id = EditEntry?.Id ?? 0; if (EditEntry != null) await EntryService.UpdateTransferAsync(EditEntry.Id, targetAccountId, date, title.Trim(), amount); else id = await EntryService.CreateTransferAsync(SourceAccountId, targetAccountId, date, title.Trim(), amount); committedResult = new(id, date, "Umbuchung", amount, EditEntry != null); } // If refreshing the page fails after commit, retry only notification, // never create a second booking. await OnSave.InvokeAsync(committedResult); completed = true; } catch (Exception ex) { saveError = committedResult == null ? "Speichern fehlgeschlagen. Die Eingaben bleiben erhalten. Bitte erneut versuchen." : "Die Buchung ist gespeichert. Die Ansicht konnte nicht aktualisiert werden. Bitte Ansicht aktualisieren; es wird keine weitere Buchung erzeugt."; saveDetails = ex.Message; Toasts.Show(saveError, Duempelkas.App.Services.ToastKind.Error, saveDetails); } finally { isSaving = false; Toasts.Dismiss(busyToast); } } private async Task Cancel() { if (!isSaving && modal != null) await modal.RequestCloseAsync(); } #endregion }