From 6062f2b1b18076d51d4bb57d349adb48076b9a05 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Tue, 27 Jan 2026 14:02:01 +0000 Subject: [PATCH] Refactor operator creation to use new command structure Refactored operator creation to use OperatorCommands.CreateOperatorCommand instead of the obsolete Commands.CreateOperatorCommand. Updated business logic, API client, and request handler to support the new command. Moved New.razor logic to code-behind, improved user feedback with success messages, and updated UI to display both error and success states. Updated test mediator for compatibility. Removed obsolete command from Commands class. --- .../Components/Pages/Operators/New.razor | 78 ++-------------- .../Components/Pages/Operators/New.razor.cs | 88 +++++++++++++++++++ .../Client/OperatorMethods.cs | 19 ++++ .../RequestHandlers/DateRequestHandler.cs | 6 +- .../Requests/Requests.cs | 3 +- .../Services/TestMediatorService.cs | 4 +- 6 files changed, 123 insertions(+), 75 deletions(-) create mode 100644 EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor.cs diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor b/EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor index 71223bc5..b71350bc 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor +++ b/EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor @@ -29,6 +29,14 @@

@errorMessage

} + + @if (!string.IsNullOrWhiteSpace(successMessage)) + { +
+

Success

+

@successMessage

+
+ }
@@ -84,72 +92,4 @@
- - -@code { - private CreateOperatorModel model = new(); - private bool isSaving = false; - private string? errorMessage; - - protected override async Task OnInitializedAsync() - { - await RequirePermission(PermissionSection.Operator, PermissionFunction.Create); - } - - private async Task HandleSubmit() - { - isSaving = true; - errorMessage = null; - - try - { - var correlationId = new CorrelationId(Guid.NewGuid()); - var estateId = Guid.Parse("11111111-1111-1111-1111-111111111111"); - var accessToken = "stubbed-token"; - - // Create operator - var createCommand = new Commands.CreateOperatorCommand( - correlationId, - accessToken, - estateId, - model.OperatorName!, - model.RequireCustomMerchantNumber, - model.RequireCustomTerminalNumber - ); - - var createResult = await Mediator.Send(createCommand); - - if (!createResult.IsSuccess) - { - errorMessage = createResult.Message ?? "Failed to create operator"; - return; - } - - // Navigate to operators list with success - NavigationManager.NavigateTo("/operators"); - } - catch (Exception ex) - { - errorMessage = $"An error occurred: {ex.Message}"; - } - finally - { - isSaving = false; - } - } - - private void Cancel() - { - NavigationManager.NavigateTo("/operators"); - } - - public class CreateOperatorModel - { - [Required(ErrorMessage = "Operator name is required")] - public string? OperatorName { get; set; } - - public bool RequireCustomMerchantNumber { get; set; } - - public bool RequireCustomTerminalNumber { get; set; } - } -} + \ No newline at end of file diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor.cs b/EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor.cs new file mode 100644 index 00000000..7f531872 --- /dev/null +++ b/EstateManagementUI.BlazorServer/Components/Pages/Operators/New.razor.cs @@ -0,0 +1,88 @@ +using EstateManagementUI.BlazorServer.Permissions; +using EstateManagementUI.BusinessLogic.Requests; +using System.ComponentModel.DataAnnotations; + +namespace EstateManagementUI.BlazorServer.Components.Pages.Operators +{ + public partial class New + { + private CreateOperatorModel model = new(); + private bool isSaving = 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.Create); + } + + private async Task HandleSubmit() + { + isSaving = true; + errorMessage = null; + + try + { + var correlationId = new CorrelationId(Guid.NewGuid()); + var estateId = await this.GetEstateId(); + + // Create operator + var createCommand = new OperatorCommands.CreateOperatorCommand( + correlationId, + estateId, + model.OperatorName!, + model.RequireCustomMerchantNumber, + model.RequireCustomTerminalNumber + ); + + var createResult = await Mediator.Send(createCommand); + + if (!createResult.IsSuccess) + { + errorMessage = createResult.Message ?? "Failed to create operator"; + return; + } + + // Show success message briefly before navigating away + successMessage = "Operator created successfully."; + StateHasChanged(); + + // Small delay so user sees confirmation (adjust duration as needed) + await Task.Delay(2500); + + + // Navigate to operators list with success + NavigationManager.NavigateTo("/operators"); + } + catch (Exception ex) + { + errorMessage = $"An error occurred: {ex.Message}"; + } + finally + { + isSaving = false; + } + } + + private void Cancel() + { + NavigationManager.NavigateTo("/operators"); + } + + public class CreateOperatorModel + { + [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 0179fee2..e07881a0 100644 --- a/EstateManagmentUI.BusinessLogic/Client/OperatorMethods.cs +++ b/EstateManagmentUI.BusinessLogic/Client/OperatorMethods.cs @@ -19,6 +19,9 @@ Task> GetOperator(OperatorQueries.GetOperatorQuery request Task UpdateOperator(OperatorCommands.UpdateOperatorCommand request, CancellationToken cancellationToken); + + Task CreateOperator(OperatorCommands.CreateOperatorCommand request, + CancellationToken cancellationToken); } public partial class ApiClient : IApiClient { @@ -71,5 +74,21 @@ public async Task UpdateOperator(OperatorCommands.UpdateOperatorCommand return Result.Success(); } + + public async Task CreateOperator(OperatorCommands.CreateOperatorCommand request, + CancellationToken cancellationToken) + { + var token = await this.GetToken(cancellationToken); + if (token.IsFailed) + return ResultHelpers.CreateFailure(token); + + var apiRequest = new CreateOperatorRequest() { Name = request.Name, RequireCustomMerchantNumber = request.RequireCustomMerchantNumber, RequireCustomTerminalNumber = request.RequireCustomTerminalNumber }; + + var apiResult = await this.TransactionProcessorClient.CreateOperator(token.Data, request.EstateId, 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 d80c4f40..d43b3ea1 100644 --- a/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs +++ b/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs @@ -224,7 +224,7 @@ public async Task>> Handle(ContractQueries.Ge public class OperatorRequestHandler : IRequestHandler>>, IRequestHandler>, - IRequestHandler, + IRequestHandler, IRequestHandler { private readonly IApiClient ApiClient; @@ -242,9 +242,9 @@ public async Task> Handle(OperatorQueries.GetOperatorQuery CancellationToken cancellationToken) { return await this.ApiClient.GetOperator(request, cancellationToken); } - public async Task Handle(Commands.CreateOperatorCommand request, + public async Task Handle(OperatorCommands.CreateOperatorCommand request, CancellationToken cancellationToken) { - return Result.Success(); + return await this.ApiClient.CreateOperator(request, cancellationToken); } public async Task Handle(OperatorCommands.UpdateOperatorCommand request, CancellationToken cancellationToken) { diff --git a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs index e77e0074..10d7c41c 100644 --- a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs +++ b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs @@ -90,6 +90,8 @@ public record CreateMerchantCommand(CorrelationId CorrelationId, Guid EstateId, public static class OperatorCommands { public record UpdateOperatorCommand(CorrelationId CorrelationId,Guid EstateId, Guid OperatorId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest; + + public record CreateOperatorCommand(CorrelationId CorrelationId, Guid EstateId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest; } public static class Commands @@ -97,7 +99,6 @@ public static class Commands public record CreateContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Description, Guid OperatorId) : IRequest; public record CreateMerchantUserCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, string EmailAddress, string Password) : IRequest; - public record CreateOperatorCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest; diff --git a/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs b/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs index a063e4f3..c90d0514 100644 --- a/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs +++ b/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs @@ -69,7 +69,7 @@ public Task Send(IRequest request, Cancellation // Commands - execute against test data store 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)), + OperatorCommands.CreateOperatorCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteCreateOperator(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)), @@ -170,7 +170,7 @@ private Result ExecuteUpdateMerchant(MerchantCommands.UpdateMerchantCommand cmd) return Result.Success(); } - private Result ExecuteCreateOperator(Commands.CreateOperatorCommand cmd) + private Result ExecuteCreateOperator(OperatorCommands.CreateOperatorCommand cmd) { var operatorModel = new OperatorModel {