using Duempelkas.App.Services.Models; using Duempelkas.Domain.Enums; using Microsoft.AspNetCore.Components; namespace Duempelkas.App.Components.Dialogs; public partial class AddEntryDialog { #region Parameters [Parameter] public int AccountId { 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; [Parameter] public string AccountName { get; set; } = string.Empty; private bool CanSave => !string.IsNullOrWhiteSpace(title) && ValidAmount && date != default && (!OutsideYear || (confirmDifferentYear && confirmedYear == date.Year)); private bool isSaving; private bool completed; private BookingSaved? committedResult; private string? saveError; private string? saveDetails; #region Fields private EntryType entryType = EntryType.Income; 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}|{entryType}"; private bool IsDirty => CurrentState != initialState; private bool initialized; private int? initializedEntryId; #endregion #region Lifecycle protected override void OnParametersSet() { if (initialized && initializedEntryId == EditEntry?.Id) return; initialized = true; initializedEntryId = EditEntry?.Id; if (EditEntry != null) { entryType = EditEntry.Type; 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.UpdateEntryAsync(EditEntry.Id, date, title.Trim(), amount); else id = (await EntryService.CreateEntryAsync(AccountId, entryType, date, title.Trim(), amount)).Id; committedResult = new(id, date, entryType == EntryType.Income ? "Einnahme" : "Ausgabe", 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 }