From 3364b659e53f04c2b1515710cdc57afa153977de Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Tue, 27 Jan 2026 12:00:59 +0000 Subject: [PATCH] Refactor Operator Edit page to use code-behind and new command - Move Operator Edit logic from Edit.razor to Edit.razor.cs for better organization and maintainability - Introduce OperatorCommands.UpdateOperatorCommand, replacing the old update command for operators - Update API client, request handler, and test mediator to use the new command - Simplify Edit.razor markup; all logic now resides in code-behind - Show a brief success message before redirecting after update - Define EditOperatorModel with validation in code-behind - Add necessary using statements and dependency injection for new structure --- .../Components/Pages/Merchants/Edit.razor.cs | 6 + .../Components/Pages/Operators/Edit.razor | 140 ------------------ .../Components/Pages/Operators/Edit.razor.cs | 133 +++++++++++++++++ .../Client/OperatorMethods.cs | 19 +++ .../RequestHandlers/DateRequestHandler.cs | 6 +- .../Requests/Requests.cs | 5 +- .../Services/TestMediatorService.cs | 4 +- 7 files changed, 167 insertions(+), 146 deletions(-) create mode 100644 EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor.cs diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs index 9201966e..f9b8ef49 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs +++ b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs @@ -230,7 +230,13 @@ private async Task SaveAllChanges() return; } + // Show success message briefly before navigating away successMessage = "Merchant details updated successfully"; + StateHasChanged(); + + // Small delay so user sees confirmation (adjust duration as needed) + await Task.Delay(2500); + // Navigate to edit page NavigationManager.NavigateTo($"/merchants"); } diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor b/EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor index 0b10b2c5..be8bf2dc 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor +++ b/EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor @@ -11,27 +11,6 @@ Edit Operator -@if (!hasPermission) -{ -
-
-
- - - -
-

Access Denied

-

You don't have permission to edit operators.

-
-
- -
-
-} -else -{
@if (isLoading) { @@ -132,122 +111,3 @@ else
} - - @code { - [Parameter] - public Guid OperatorId { get; set; } - - private OperatorModel? operatorModel; - private EditOperatorModel model = new(); - private bool isLoading = true; - private bool isSaving = false; - private bool hasPermission = false; - private string? errorMessage; - private string? successMessage; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (!firstRender) - { - await base.OnAfterRenderAsync(firstRender); - return; - } - - await RequirePermission(PermissionSection.Operator, PermissionFunction.Edit); - await LoadOperator(); - } - - private async Task LoadOperator() - { - try - { - isLoading = true; - var correlationId = new CorrelationId(Guid.NewGuid()); - var estateId = await GetEstateId(); - - var result = await Mediator.Send(new OperatorQueries.GetOperatorQuery(correlationId, estateId, OperatorId)); - - if (result.IsSuccess && result.Data != null) - { - operatorModel = ModelFactory.ConvertFrom(result.Data); - - // Initialize model with current values - model = new EditOperatorModel - { - OperatorName = operatorModel.Name, - RequireCustomMerchantNumber = operatorModel.RequireCustomMerchantNumber, - RequireCustomTerminalNumber = operatorModel.RequireCustomTerminalNumber - }; - } - } - finally - { - isLoading = false; - } - } - - private async Task HandleSubmit() - { - isSaving = true; - ClearMessages(); - - try - { - var correlationId = new CorrelationId(Guid.NewGuid()); - var estateId = Guid.Parse("11111111-1111-1111-1111-111111111111"); - var accessToken = "stubbed-token"; - - var command = new Commands.UpdateOperatorCommand( - correlationId, - accessToken, - estateId, - OperatorId, - model.OperatorName!, - model.RequireCustomMerchantNumber, - model.RequireCustomTerminalNumber - ); - - var result = await Mediator.Send(command); - - if (result.IsSuccess) - { - successMessage = "Operator updated successfully"; - await LoadOperator(); - } - else - { - errorMessage = result.Message ?? "Failed to update operator"; - } - } - catch (Exception ex) - { - errorMessage = $"An error occurred: {ex.Message}"; - } - finally - { - isSaving = false; - } - } - - private void ClearMessages() - { - errorMessage = null; - successMessage = null; - } - - private void BackToList() - { - NavigationManager.NavigateTo("/operators"); - } - - public class EditOperatorModel - { - [Required(ErrorMessage = "Operator name is required")] - public string? OperatorName { get; set; } - - public bool RequireCustomMerchantNumber { get; set; } - - public bool RequireCustomTerminalNumber { get; set; } - } -} -} diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor.cs b/EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor.cs new file mode 100644 index 00000000..b0feb206 --- /dev/null +++ b/EstateManagementUI.BlazorServer/Components/Pages/Operators/Edit.razor.cs @@ -0,0 +1,133 @@ +using EstateManagementUI.BlazorServer.Factories; +using EstateManagementUI.BlazorServer.Permissions; +using EstateManagementUI.BusinessLogic.Requests; +using MediatR; +using Microsoft.AspNetCore.Components; +using System.ComponentModel.DataAnnotations; +using EstateManagementUI.BlazorServer.Models; + +namespace EstateManagementUI.BlazorServer.Components.Pages.Operators +{ + public partial class Edit + { + [Parameter] + public Guid OperatorId { get; set; } + + private OperatorModel? operatorModel; + private EditOperatorModel model = new(); + private bool isLoading = true; + private bool isSaving = false; + private bool hasPermission = false; + private string? errorMessage; + private string? successMessage; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (!firstRender) + { + await base.OnAfterRenderAsync(firstRender); + return; + } + + await RequirePermission(PermissionSection.Operator, PermissionFunction.Edit); + await LoadOperator(); + } + + private async Task LoadOperator() + { + try + { + isLoading = true; + var correlationId = new CorrelationId(Guid.NewGuid()); + var estateId = await GetEstateId(); + + var result = await Mediator.Send(new OperatorQueries.GetOperatorQuery(correlationId, estateId, OperatorId)); + + if (result.IsSuccess && result.Data != null) + { + operatorModel = ModelFactory.ConvertFrom(result.Data); + + // Initialize model with current values + model = new EditOperatorModel + { + OperatorName = operatorModel.Name, + RequireCustomMerchantNumber = operatorModel.RequireCustomMerchantNumber, + RequireCustomTerminalNumber = operatorModel.RequireCustomTerminalNumber + }; + } + } + finally + { + isLoading = false; + this.StateHasChanged(); + } + } + + private async Task HandleSubmit() + { + isSaving = true; + ClearMessages(); + + try + { + var correlationId = new CorrelationId(Guid.NewGuid()); + var estateId = await this.GetEstateId(); + + var command = new OperatorCommands.UpdateOperatorCommand( + correlationId, + estateId, + OperatorId, + model.OperatorName!, + model.RequireCustomMerchantNumber, + model.RequireCustomTerminalNumber + ); + + var result = await Mediator.Send(command); + + if (result.IsSuccess) + { + successMessage = "Operator updated successfully"; + StateHasChanged(); + + // Small delay so user sees confirmation (adjust duration as needed) + await Task.Delay(2500); + + NavigationManager.NavigateTo("/operators"); + } + else + { + errorMessage = result.Message ?? "Failed to update operator"; + } + } + catch (Exception ex) + { + errorMessage = $"An error occurred: {ex.Message}"; + } + finally + { + isSaving = false; + } + } + + private void ClearMessages() + { + errorMessage = null; + successMessage = null; + } + + private void BackToList() + { + NavigationManager.NavigateTo("/operators"); + } + + public class EditOperatorModel + { + [Required(ErrorMessage = "Operator name is required")] + public string? OperatorName { get; set; } + + public bool RequireCustomMerchantNumber { get; set; } + + public bool RequireCustomTerminalNumber { get; set; } + } + } +} diff --git a/EstateManagmentUI.BusinessLogic/Client/OperatorMethods.cs b/EstateManagmentUI.BusinessLogic/Client/OperatorMethods.cs index ebcd022a..0179fee2 100644 --- a/EstateManagmentUI.BusinessLogic/Client/OperatorMethods.cs +++ b/EstateManagmentUI.BusinessLogic/Client/OperatorMethods.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Text; +using TransactionProcessor.DataTransferObjects.Requests.Operator; namespace EstateManagementUI.BusinessLogic.Client { @@ -15,6 +16,9 @@ Task>> GetOperators(OperatorQueries.GetOperatorsQuery Task> GetOperator(OperatorQueries.GetOperatorQuery request, CancellationToken cancellationToken); + + Task UpdateOperator(OperatorCommands.UpdateOperatorCommand request, + CancellationToken cancellationToken); } public partial class ApiClient : IApiClient { @@ -52,5 +56,20 @@ public async Task> GetOperator(OperatorQueries.GetOperator return Result.Success(operatorModels); } + + public async Task UpdateOperator(OperatorCommands.UpdateOperatorCommand request, + CancellationToken cancellationToken) { + var token = await this.GetToken(cancellationToken); + if (token.IsFailed) + return ResultHelpers.CreateFailure(token); + + var apiRequest = new UpdateOperatorRequest() { Name= request.Name, RequireCustomMerchantNumber = request.RequireCustomMerchantNumber, RequireCustomTerminalNumber = request.RequireCustomTerminalNumber}; + + var apiResult = await this.TransactionProcessorClient.UpdateOperator(token.Data, request.EstateId, request.OperatorId, apiRequest, cancellationToken); + if (apiResult.IsFailed) + return ResultHelpers.CreateFailure(apiResult); + + return Result.Success(); + } } } diff --git a/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs b/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs index 41f60e96..d80c4f40 100644 --- a/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs +++ b/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs @@ -225,7 +225,7 @@ public async Task>> Handle(ContractQueries.Ge public class OperatorRequestHandler : IRequestHandler>>, IRequestHandler>, IRequestHandler, - IRequestHandler + IRequestHandler { private readonly IApiClient ApiClient; @@ -246,9 +246,9 @@ public async Task Handle(Commands.CreateOperatorCommand request, CancellationToken cancellationToken) { return Result.Success(); } - public async Task Handle(Commands.UpdateOperatorCommand request, + public async Task Handle(OperatorCommands.UpdateOperatorCommand request, CancellationToken cancellationToken) { - return Result.Success(); + return await this.ApiClient.UpdateOperator(request, cancellationToken); } } diff --git a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs index 0c9383b0..e77e0074 100644 --- a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs +++ b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs @@ -88,6 +88,10 @@ public record MakeMerchantDepositCommand(CorrelationId CorrelationId, Guid Estat public record CreateMerchantCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string Name, String SettlementSchedule, MerchantAddress MerchantAddress, MerchantContact MerchantContact) : IRequest; } +public static class OperatorCommands { + public record UpdateOperatorCommand(CorrelationId CorrelationId,Guid EstateId, Guid OperatorId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest; +} + public static class Commands { @@ -97,7 +101,6 @@ public record CreateOperatorCommand(CorrelationId CorrelationId, string AccessTo - public record UpdateOperatorCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid OperatorId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest; public record AddProductToContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid ContractId, string ProductName, string DisplayText, decimal? Value) : IRequest; public record AddTransactionFeeForProductToContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid ContractId, Guid ProductId, string Description, decimal Value) : IRequest; } diff --git a/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs b/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs index dc8cb7ee..a063e4f3 100644 --- a/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs +++ b/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs @@ -70,7 +70,7 @@ public Task Send(IRequest request, Cancellation MerchantCommands.CreateMerchantCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteCreateMerchant(cmd)), MerchantCommands.UpdateMerchantCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteUpdateMerchant(cmd)), Commands.CreateOperatorCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteCreateOperator(cmd)), - Commands.UpdateOperatorCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteUpdateOperator(cmd)), + OperatorCommands.UpdateOperatorCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteUpdateOperator(cmd)), Commands.CreateContractCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteCreateContract(cmd)), Commands.AddProductToContractCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteAddProductToContract(cmd)), Commands.AddTransactionFeeForProductToContractCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteAddTransactionFee(cmd)), @@ -183,7 +183,7 @@ private Result ExecuteCreateOperator(Commands.CreateOperatorCommand cmd) return Result.Success(); } - private Result ExecuteUpdateOperator(Commands.UpdateOperatorCommand cmd) + private Result ExecuteUpdateOperator(OperatorCommands.UpdateOperatorCommand cmd) { var operatorModel = this._testDataStore.GetOperator(cmd.EstateId, cmd.OperatorId); if (operatorModel == null)