feat(usability): confirm saves and guard booking submissions against duplicates (U07)

This commit is contained in:
2026-11-02 06:38:42 +01:00
parent 76ba79b63e
commit 22e509d982
17 changed files with 373 additions and 118 deletions
@@ -15,7 +15,7 @@ public partial class AddEntryDialog
public EntryDto? EditEntry { get; set; }
[Parameter]
public EventCallback<DateTime> OnSave { get; set; }
public EventCallback<BookingSaved> OnSave { get; set; }
[Parameter]
public EventCallback OnCancel { get; set; }
@@ -30,6 +30,12 @@ public partial class AddEntryDialog
[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;
@@ -66,20 +72,40 @@ public partial class AddEntryDialog
private async Task Save()
{
if (!CanSave) return;
if (EditEntry != null)
if (isSaving || completed || (committedResult == null && !CanSave)) return;
isSaving = true;
saveError = null;
saveDetails = null;
try
{
await EntryService.UpdateEntryAsync(EditEntry.Id, date, title.Trim(), amount);
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;
}
else
catch (Exception ex)
{
await EntryService.CreateEntryAsync(AccountId, entryType, date, title.Trim(), amount);
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;
}
await OnSave.InvokeAsync(date);
finally { isSaving = false; }
}
private async Task Cancel() => await OnCancel.InvokeAsync();
private async Task Cancel()
{
if (!isSaving) await OnCancel.InvokeAsync();
}
#endregion
}