From 027a36ce171e51ff4deada16bba9c39c9aec1486 Mon Sep 17 00:00:00 2001 From: Andre Beging Date: Fri, 28 Mar 2025 23:55:12 +0100 Subject: [PATCH] Refactor interaction and user deletion logic Consolidated repeated methods for interaction/user deletion into reusable components to improve maintainability. Introduced a `ConfirmDialog` for consistent confirmation UI and streamlined associated logic across pages. Removed redundant methods and enhanced admin-specific page security checks. --- FoodsharingSiegen.Server/App.razor | 7 +- .../BaseClasses/FsBase.cs | 6 - .../Controls/ProspectContainer.razor.cs | 104 +++++++++++------- .../Dialogs/ConfirmDialog.razor | 10 ++ .../Dialogs/ConfirmDialog.razor.cs | 63 +++++++++++ .../Pages/Prospects.razor.cs | 26 ----- .../Pages/ProspectsAll.razor | 4 +- .../Pages/ProspectsAll.razor.cs | 43 +------- .../Pages/ProspectsDone.razor.cs | 26 ----- .../Pages/ProspectsVerify.razor.cs | 40 ------- FoodsharingSiegen.Server/Pages/Users.razor | 5 +- FoodsharingSiegen.Server/Pages/Users.razor.cs | 74 +++++-------- 12 files changed, 174 insertions(+), 234 deletions(-) create mode 100644 FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor create mode 100644 FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor.cs diff --git a/FoodsharingSiegen.Server/App.razor b/FoodsharingSiegen.Server/App.razor index 83c0552..1c9b1e8 100644 --- a/FoodsharingSiegen.Server/App.razor +++ b/FoodsharingSiegen.Server/App.razor @@ -1,4 +1,4 @@ - + @@ -13,15 +13,14 @@ - @code{ - private Theme theme = new() + private readonly Theme _theme = new() { - ColorOptions = new ThemeColorOptions + ColorOptions = new() { Primary = "#64ae24", Secondary = "#533a20", diff --git a/FoodsharingSiegen.Server/BaseClasses/FsBase.cs b/FoodsharingSiegen.Server/BaseClasses/FsBase.cs index fec127f..f7120ad 100644 --- a/FoodsharingSiegen.Server/BaseClasses/FsBase.cs +++ b/FoodsharingSiegen.Server/BaseClasses/FsBase.cs @@ -31,12 +31,6 @@ namespace FoodsharingSiegen.Server.BaseClasses [Inject] protected AuthService AuthService { get; set; } = null!; - /// - /// Gets or sets the value of the message (ab) - /// - [Inject] - protected IMessageService Message { get; set; } = null!; - /// /// Gets or sets the modal service for handling modals within the application /// diff --git a/FoodsharingSiegen.Server/Controls/ProspectContainer.razor.cs b/FoodsharingSiegen.Server/Controls/ProspectContainer.razor.cs index 93764a4..5dceb2c 100644 --- a/FoodsharingSiegen.Server/Controls/ProspectContainer.razor.cs +++ b/FoodsharingSiegen.Server/Controls/ProspectContainer.razor.cs @@ -8,59 +8,83 @@ namespace FoodsharingSiegen.Server.Controls { public partial class ProspectContainer { - [Parameter] public Prospect? Prospect { get; set; } - - [Parameter] public ProspectStateFilter StateFilter { get; set; } - - [Parameter] public string? CssClass { get; set; } - - [Parameter] public Func? OnDataChanged { get; set; } - - - private async Task AddInteraction(InteractionType type) - { - if (Prospect != null && OnDataChanged != null) - { - var headerText = $"{type.Translate(AppSettings)} eintragen"; - - await InteractionDialog.ShowAsync(ModalService, new(type, Prospect.Id, headerText, OnDataChanged)); - } - - } - - private List GetTyped(InteractionType type) - { - return Prospect?.Interactions?.Where(x => x.Type == type).ToList() ?? []; - } - - private async Task EditProspectAsync() - { - await EditProspectDialog.ShowAsync(ModalService, () => InvokeAsync(StateHasChanged), Prospect); - } + #region Dependencies /// /// Gets or sets the value of the prospect service (ab) /// [Inject] public ProspectService ProspectService { get; set; } = null!; - + + #endregion + + #region Parameters + + [Parameter] + public string? CssClass { get; set; } + + [Parameter] + public Func? OnDataChanged { get; set; } + + [Parameter] + public Prospect? Prospect { get; set; } + + [Parameter] + public ProspectStateFilter StateFilter { get; set; } + + #endregion + + #region Private Method AddInteraction + + private async Task AddInteraction(InteractionType type) + { + if (Prospect != null && OnDataChanged != null) + { + var headerText = $"{type.Translate(AppSettings)} eintragen"; + + await InteractionDialog.ShowAsync(ModalService, new(type, Prospect.Id, headerText, OnDataChanged)); + } + } + + #endregion + + #region Private Method EditProspectAsync + + private async Task EditProspectAsync() + { + await EditProspectDialog.ShowAsync(ModalService, () => InvokeAsync(StateHasChanged), Prospect); + } + + #endregion + + #region Private Method GetTyped + + private List GetTyped(InteractionType type) + { + return Prospect?.Interactions?.Where(x => x.Type == type).ToList() ?? []; + } + + #endregion + + #region Private Method RemoveInteraction + + /// + /// Removes a specified interaction by its identifier. Displays a confirmation dialog to the user before performing the removal. + /// + /// The unique identifier of the interaction to be removed. + /// A task that represents the asynchronous operation. private async Task RemoveInteraction(Guid arg) { var type = Prospect?.Interactions.FirstOrDefault(x => x.Id == arg)?.Type; var typeName = type != null ? type.Value.Translate(AppSettings) : "Interaktion"; - - var confirm = await Message.Confirm($"{typeName} wirklich entfernen?", "Bestätigen", o => - { - o.ConfirmButtonText = "Ja, wirklich!"; - o.CancelButtonText = "Abbrechen"; - o.ShowMessageIcon = false; - }); - if (confirm) + await ConfirmDialog.ShowAsync(ModalService, "Bestätigen", $"{typeName} wirklich entfernen?", async () => { var removeR = await ProspectService.RemoveInteraction(arg); - if(removeR.Success && OnDataChanged != null) await OnDataChanged(); - } + if (removeR.Success && OnDataChanged != null) await OnDataChanged(); + }); } + + #endregion } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor b/FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor new file mode 100644 index 0000000..4ef729b --- /dev/null +++ b/FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor @@ -0,0 +1,10 @@ +@inherits FsBase + +
+ @Message +
+ +
+ + +
\ No newline at end of file diff --git a/FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor.cs b/FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor.cs new file mode 100644 index 0000000..3d66a42 --- /dev/null +++ b/FoodsharingSiegen.Server/Dialogs/ConfirmDialog.razor.cs @@ -0,0 +1,63 @@ +using Blazorise; +using FoodsharingSiegen.Server.BaseClasses; +using Microsoft.AspNetCore.Components; + +namespace FoodsharingSiegen.Server.Dialogs +{ + public partial class ConfirmDialog : FsBase + { + #region Parameters + + [Parameter] + public Func? OnConfirm { get; set; } + + [Parameter] + public string? Message { get; set; } + + #endregion + + #region Public Method ShowAsync + + /// + /// Displays the confirm dialog with the specified title, message, and confirmation action. + /// + /// The modal service used to display the dialog. + /// The title of the confirmation dialog. Defaults to "Bestätigen" if null. + /// The message displayed in the confirmation dialog. + /// The action to invoke when the user confirms. + /// A task that represents the asynchronous operation of displaying the dialog. + public static async Task ShowAsync(IModalService modalService, string? title, string? message, Func onConfirm) + { + title ??= "Bestätigen"; + + var x = new Action>(b => + { + b.Add(nameof(OnConfirm), onConfirm); + b.Add(nameof(Message), message); + }); + + var options = new ModalInstanceOptions + { + Size = ModalSize.Small + }; + + await modalService.Show(title, x, options); + } + + #endregion + + #region Private Method ConfirmClickAsync + + /// + /// Invokes the confirmation action if it is set. + /// + /// A task that represents the asynchronous operation. + private async Task ConfirmClickAsync() + { + if (OnConfirm != null) await OnConfirm.Invoke(); + await ModalService.Hide(); + } + + #endregion + } +} \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Pages/Prospects.razor.cs b/FoodsharingSiegen.Server/Pages/Prospects.razor.cs index 529b243..3c19d5d 100644 --- a/FoodsharingSiegen.Server/Pages/Prospects.razor.cs +++ b/FoodsharingSiegen.Server/Pages/Prospects.razor.cs @@ -81,31 +81,5 @@ namespace FoodsharingSiegen.Server.Pages } #endregion - - #region Private Method RemoveInteractionAsync - - /// - /// Removes the interaction using the specified arg (a. beging, 11.04.2022) - /// - /// The arg - private async Task RemoveInteractionAsync(Guid arg) - { - var confirm = await Message.Confirm("Interaktion wirklich löschen?", "Bestätigen", o => - { - o.ConfirmButtonText = "Ja, wirklich!"; - o.CancelButtonText = "Abbrechen"; - o.ShowMessageIcon = false; - }); - - if (confirm) - { - await ProspectService.RemoveInteraction(arg); - await LoadProspects(); - } - - await InvokeAsync(StateHasChanged); - } - - #endregion } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Pages/ProspectsAll.razor b/FoodsharingSiegen.Server/Pages/ProspectsAll.razor index bb3b6b0..441cf6a 100644 --- a/FoodsharingSiegen.Server/Pages/ProspectsAll.razor +++ b/FoodsharingSiegen.Server/Pages/ProspectsAll.razor @@ -3,9 +3,9 @@ @using FoodsharingSiegen.Shared.Helper @inherits FsBase -Freischalten - @AppSettings.Terms.Title +Alle (Admin) - @AppSettings.Terms.Title -

Freischalten

+

Alle (Admin)

@{ var filterList = ProspectList.ApplyFilter(Filter); diff --git a/FoodsharingSiegen.Server/Pages/ProspectsAll.razor.cs b/FoodsharingSiegen.Server/Pages/ProspectsAll.razor.cs index 52e1df6..35af4bd 100644 --- a/FoodsharingSiegen.Server/Pages/ProspectsAll.razor.cs +++ b/FoodsharingSiegen.Server/Pages/ProspectsAll.razor.cs @@ -1,4 +1,5 @@ using FoodsharingSiegen.Contracts.Entity; +using FoodsharingSiegen.Contracts.Helper; using FoodsharingSiegen.Contracts.Model; using FoodsharingSiegen.Server.Data.Service; using FoodsharingSiegen.Server.Dialogs; @@ -43,6 +44,8 @@ namespace FoodsharingSiegen.Server.Pages /// protected override async Task InitializeDataAsync() { + if(!CurrentUser.IsAdmin()) NavigationManager.NavigateTo("/"); + // Load prospects await LoadProspects(); } @@ -64,45 +67,5 @@ namespace FoodsharingSiegen.Server.Pages } #endregion - - #region Private Method OnUpdateProspect - - /// - /// Ons the update prospect using the specified prospect (a. beging, 11.04.2022) - /// - /// The prospect - private async Task OnUpdateProspect(Prospect prospect) - { - var updateProspectR = await ProspectService.UpdateAsync(prospect); - if (updateProspectR.Success) await LoadProspects(); - } - - #endregion - - #region Private Method RemoveInteraction - - /// - /// Removes the interaction using the specified arg (a. beging, 11.04.2022) - /// - /// The arg - private async Task RemoveInteraction(Guid arg) - { - var confirm = await Message.Confirm("Interaktion wirklich löschen?", "Bestätigen", o => - { - o.ConfirmButtonText = "Ja, wirklich!"; - o.CancelButtonText = "Abbrechen"; - o.ShowMessageIcon = false; - }); - - if (confirm) - { - await ProspectService.RemoveInteraction(arg); - await LoadProspects(); - } - - await InvokeAsync(StateHasChanged); - } - - #endregion } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Pages/ProspectsDone.razor.cs b/FoodsharingSiegen.Server/Pages/ProspectsDone.razor.cs index 4987cf7..48480e0 100644 --- a/FoodsharingSiegen.Server/Pages/ProspectsDone.razor.cs +++ b/FoodsharingSiegen.Server/Pages/ProspectsDone.razor.cs @@ -56,31 +56,5 @@ namespace FoodsharingSiegen.Server.Pages } #endregion - - #region Private Method RemoveInteraction - - /// - /// Removes the interaction using the specified arg (a. beging, 11.04.2022) - /// - /// The arg - private async Task RemoveInteraction(Guid arg) - { - var confirm = await Message.Confirm("Interaktion wirklich löschen?", "Bestätigen", o => - { - o.ConfirmButtonText = "Ja, wirklich!"; - o.CancelButtonText = "Abbrechen"; - o.ShowMessageIcon = false; - }); - - if (confirm) - { - await ProspectService.RemoveInteraction(arg); - await LoadProspects(); - } - - await InvokeAsync(StateHasChanged); - } - - #endregion } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Pages/ProspectsVerify.razor.cs b/FoodsharingSiegen.Server/Pages/ProspectsVerify.razor.cs index 338f07f..e6b2ab4 100644 --- a/FoodsharingSiegen.Server/Pages/ProspectsVerify.razor.cs +++ b/FoodsharingSiegen.Server/Pages/ProspectsVerify.razor.cs @@ -68,45 +68,5 @@ namespace FoodsharingSiegen.Server.Pages } #endregion - - #region Private Method OnUpdateProspect - - /// - /// Ons the update prospect using the specified prospect (a. beging, 11.04.2022) - /// - /// The prospect - private async Task OnUpdateProspect(Prospect prospect) - { - var updateProspectR = await ProspectService.UpdateAsync(prospect); - if (updateProspectR.Success) await LoadProspects(); - } - - #endregion - - #region Private Method RemoveInteraction - - /// - /// Removes the interaction using the specified arg (a. beging, 11.04.2022) - /// - /// The arg - private async Task RemoveInteraction(Guid arg) - { - var confirm = await Message.Confirm("Interaktion wirklich löschen?", "Bestätigen", o => - { - o.ConfirmButtonText = "Ja, wirklich!"; - o.CancelButtonText = "Abbrechen"; - o.ShowMessageIcon = false; - }); - - if (confirm) - { - await ProspectService.RemoveInteraction(arg); - await LoadProspects(); - } - - await InvokeAsync(StateHasChanged); - } - - #endregion } } \ No newline at end of file diff --git a/FoodsharingSiegen.Server/Pages/Users.razor b/FoodsharingSiegen.Server/Pages/Users.razor index a1a34cb..593f68a 100644 --- a/FoodsharingSiegen.Server/Pages/Users.razor +++ b/FoodsharingSiegen.Server/Pages/Users.razor @@ -38,10 +38,7 @@ PopupTitleTemplate="PopupTitleTemplate" RowInserted="RowInserted" RowUpdated="RowUpdated" - RowRemoving="RowRemoving" - RowRemoved="RowRemoved" PageSize="50" - @bind-SelectedRow="SelectedUser" RowDoubleClicked="arg => UserDataGrid?.Edit(arg.Item)!" Editable @@ -59,7 +56,7 @@ - diff --git a/FoodsharingSiegen.Server/Pages/Users.razor.cs b/FoodsharingSiegen.Server/Pages/Users.razor.cs index e54ba0d..a893567 100644 --- a/FoodsharingSiegen.Server/Pages/Users.razor.cs +++ b/FoodsharingSiegen.Server/Pages/Users.razor.cs @@ -1,4 +1,3 @@ -using Blazorise; using Blazorise.DataGrid; using FoodsharingSiegen.Contracts.Entity; using FoodsharingSiegen.Contracts.Helper; @@ -63,6 +62,7 @@ namespace FoodsharingSiegen.Server.Pages /// protected override async Task InitializeDataAsync() { + if (!CurrentUser.IsAdmin()) NavigationManager.NavigateTo("/"); await LoadUsers(); } @@ -98,6 +98,33 @@ namespace FoodsharingSiegen.Server.Pages #endregion + #region Private Method RemoveUserAsync + + /// + /// Removes the specified user if they are not an admin, after confirming the action with a dialog. + /// + /// The user to be removed. + /// A task that represents the asynchronous remove operation. + private async Task RemoveUserAsync(User user) + { + if (user.IsAdmin()) + { + await Notification.Error("Admins können nicht gelöscht werden!"); + return; + } + + await ConfirmDialog.ShowAsync(ModalService, "Bestätigen", $"User {user.Mail} löschen?", async () => + { + var removeR = await UserService.RemoveAsync(user.Id); + if (!removeR.Success) + await Notification.Error($"Löschen: {removeR.ErrorMessage}")!; + else + await LoadUsers(); + }); + } + + #endregion + #region Private Method RowInserted /// @@ -115,51 +142,6 @@ namespace FoodsharingSiegen.Server.Pages #endregion - #region Private Method RowRemoved - - /// - /// Rows the removed using the specified arg (a. beging, 08.02.2023) - /// - /// The arg - private async Task RowRemoved(User arg) - { - var removeR = await UserService.RemoveAsync(arg.Id); - if (!removeR.Success) - await Notification.Error($"Löschen: {removeR.ErrorMessage}")!; - else - await LoadUsers(); - } - - #endregion - - #region Private Method RowRemoving - - /// - /// Rows the removing using the specified arg (a. beging, 08.02.2023) - /// - /// The arg - private async Task RowRemoving(CancellableRowChange arg) - { - if (arg.Item.IsAdmin()) - { - await Notification.Error("Admins können nicht gelöscht werden!"); - arg.Cancel = true; - return; - } - - var confirm = await Message.Confirm($"User {arg.Item.Mail} löschen?", "Bestätigen", o => - { - o.ConfirmButtonText = "Löschen"; - o.CancelButtonText = "Abbrechen"; - o.ShowMessageIcon = false; - o.ConfirmButtonColor = Color.Danger; - }); - - arg.Cancel = !confirm; - } - - #endregion - #region Private Method RowUpdated ///