diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor index 87e1f347..b853143c 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor +++ b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor @@ -323,7 +323,7 @@ @if (assignedDevices == null || !assignedDevices.Any()) {

No devices assigned

} - else { + @* else {
@foreach (var device in assignedDevices) {
@@ -334,7 +334,42 @@
}
- } + } *@ + else { +
+ @foreach (var device in assignedDevices) { +
+
+ @device.DeviceIdentifier +
+ + @if (selectedDeviceToSwap == device.DeviceIdentifier) { +
+ + + +
+ } + else { +
+ +
+ } +
+ + @if (selectedDeviceToSwap == device.DeviceIdentifier && !string.IsNullOrEmpty(swapDeviceError)) + { +

@swapDeviceError

+ } + } +
+ } } diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs index fd8ebc24..5dbd7ed6 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs +++ b/EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs @@ -2,7 +2,9 @@ using EstateManagementUI.BlazorServer.Factories; using EstateManagementUI.BlazorServer.Models; using EstateManagementUI.BlazorServer.Permissions; +using EstateManagementUI.BusinessLogic.BackendAPI.DataTransferObjects; using EstateManagementUI.BusinessLogic.Requests; +using MediatR; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Forms; using Shared.Results; @@ -490,21 +492,12 @@ private async Task AddDeviceToMerchant() try { var correlationId = new CorrelationId(Guid.NewGuid()); - var estateId = Guid.Parse("11111111-1111-1111-1111-111111111111"); - var accessToken = "stubbed-token"; - - var command = new Commands.AddMerchantDeviceCommand( - correlationId, - accessToken, - estateId, - MerchantId, - deviceIdentifier - ); + var estateId = await this.GetEstateId(); + IRequest command = new MerchantCommands.AddMerchantDeviceCommand(correlationId, estateId, MerchantId, deviceIdentifier); var result = await Mediator.Send(command); - if (result.IsSuccess) - { + if (result.IsSuccess) { successMessage = "Device added successfully"; assignedDevices.Add(new MerchantDeviceModel() { DeviceIdentifier = this.deviceIdentifier @@ -523,15 +516,71 @@ private async Task AddDeviceToMerchant() } } - private void RemoveDevice(string device) - { - ClearMessages(); - var d = this.assignedDevices.Single(d => d.DeviceIdentifier == device); - assignedDevices.Remove(d); - successMessage = "Device removed successfully"; + // inside partial class Edit (add the following fields and methods) + + // Swap device UI state + private string? selectedDeviceToSwap; + private string? swapDeviceIdentifier; + private string? swapDeviceError; + + private void StartSwapDevice(string device) + { + ClearMessages(); + selectedDeviceToSwap = device; + swapDeviceIdentifier = string.Empty; + swapDeviceError = null; + } + + private void CancelSwapDevice() + { + swapDeviceIdentifier = null; + swapDeviceError = null; + selectedDeviceToSwap = null; + } + + private async Task SwapDeviceConfirm(string originalDevice) + { + ClearMessages(); + + var newId = swapDeviceIdentifier?.Trim(); + + // Validation + if (string.IsNullOrWhiteSpace(newId)) { + swapDeviceError = "New device identifier is required."; + return; } - private void ClearMessages() + // Case-insensitive comparison for equality/duplicates + if (string.Equals(originalDevice?.Trim(), newId, StringComparison.OrdinalIgnoreCase)) { + swapDeviceError = "New device identifier cannot be the same as the current device."; + return; + } + + if (assignedDevices.Any(d => string.Equals(d.DeviceIdentifier.Trim(), newId, StringComparison.OrdinalIgnoreCase))) { + swapDeviceError = "The specified device identifier is already assigned."; + return; + } + + var correlationId = new CorrelationId(Guid.NewGuid()); + var estateId = await this.GetEstateId(); + var command = new MerchantCommands.SwapMerchantDeviceCommand(correlationId, estateId, this.MerchantId, this.assignedDevices.Single().DeviceIdentifier, newId); + + var result = await Mediator.Send(command); + + if (result.IsSuccess) { + successMessage = $"Device {originalDevice} swapped for {newId}."; + } + else { + swapDeviceError = "Original device not found."; + } + + // Reset swap UI + CancelSwapDevice(); + StateHasChanged(); + } + + + private void ClearMessages() { errorMessage = null; successMessage = null; diff --git a/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs b/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs index 7d1ba585..5d3965e4 100644 --- a/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs +++ b/EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs @@ -26,6 +26,8 @@ public partial interface IApiClient Task AddOperatorToMerchant(MerchantCommands.AddOperatorToMerchantCommand request, CancellationToken cancellationToken); Task RemoveContractFromMerchant(MerchantCommands.RemoveContractFromMerchantCommand request, CancellationToken cancellationToken); Task AddContractToMerchant(MerchantCommands.AssignContractToMerchantCommand request, CancellationToken cancellationToken); + Task AddDeviceToMerchant(MerchantCommands.AddMerchantDeviceCommand request, CancellationToken cancellationToken); + Task SwapMerchantDevice(MerchantCommands.SwapMerchantDeviceCommand request, CancellationToken cancellationToken); } public partial class ApiClient : IApiClient { @@ -74,6 +76,36 @@ public async Task AddContractToMerchant(MerchantCommands.AssignContractT return Result.Success(); } + public async Task AddDeviceToMerchant(MerchantCommands.AddMerchantDeviceCommand request, + CancellationToken cancellationToken) { + var token = await this.GetToken(cancellationToken); + if (token.IsFailed) + return ResultHelpers.CreateFailure(token); + + AddMerchantDeviceRequest apiRequest = new() { DeviceIdentifier = request.DeviceIdentifier}; + + var apiResult = await this.TransactionProcessorClient.AddDeviceToMerchant(token.Data, request.EstateId, request.MerchantId, apiRequest, cancellationToken); + if (apiResult.IsFailed) + return ResultHelpers.CreateFailure(apiResult); + + return Result.Success(); + } + + public async Task SwapMerchantDevice(MerchantCommands.SwapMerchantDeviceCommand request, + CancellationToken cancellationToken) { + var token = await this.GetToken(cancellationToken); + if (token.IsFailed) + return ResultHelpers.CreateFailure(token); + + SwapMerchantDeviceRequest apiRequest = new() { NewDeviceIdentifier = request.NewDevice}; + + var apiResult = await this.TransactionProcessorClient.SwapDeviceForMerchant(token.Data, request.EstateId, request.MerchantId, request.OldDevice,apiRequest, cancellationToken); + if (apiResult.IsFailed) + return ResultHelpers.CreateFailure(apiResult); + + return Result.Success(); + } + public async Task RemoveOperatorFromMerchant(MerchantCommands.RemoveOperatorFromMerchantCommand request, CancellationToken cancellationToken) { var token = await this.GetToken(cancellationToken); diff --git a/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs b/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs index 33a19ba7..2c806642 100644 --- a/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs +++ b/EstateManagmentUI.BusinessLogic/RequestHandlers/DateRequestHandler.cs @@ -54,13 +54,13 @@ public async Task>> Handle(EstateQueries.GetAssignedO public class MerchantRequestHandler : IRequestHandler>>, IRequestHandler>, - IRequestHandler, + IRequestHandler, IRequestHandler, IRequestHandler, IRequestHandler, IRequestHandler, IRequestHandler, - IRequestHandler, + IRequestHandler, IRequestHandler, IRequestHandler, IRequestHandler>>, @@ -82,9 +82,9 @@ public async Task>> Handle(MerchantQueries.GetMer return await this.ApiClient.GetMerchants(request, cancellationToken); } - public async Task Handle(Commands.AddMerchantDeviceCommand request, + public async Task Handle(MerchantCommands.AddMerchantDeviceCommand request, CancellationToken cancellationToken) { - return Result.Success(); + return await this.ApiClient.AddDeviceToMerchant(request, cancellationToken); } public async Task Handle(MerchantCommands.AddOperatorToMerchantCommand request, @@ -112,9 +112,9 @@ public async Task Handle(MerchantCommands.RemoveOperatorFromMerchantComm return await this.ApiClient.RemoveOperatorFromMerchant(request, cancellationToken); } - public async Task Handle(Commands.SwapMerchantDeviceCommand request, + public async Task Handle(MerchantCommands.SwapMerchantDeviceCommand request, CancellationToken cancellationToken) { - return Result.Success(); + return await this.ApiClient.SwapMerchantDevice(request, cancellationToken); } diff --git a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs index 5d397a67..d0862972 100644 --- a/EstateManagmentUI.BusinessLogic/Requests/Requests.cs +++ b/EstateManagmentUI.BusinessLogic/Requests/Requests.cs @@ -82,18 +82,20 @@ public record RemoveOperatorFromMerchantCommand(CorrelationId CorrelationId, Gui public record AddOperatorToMerchantCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, Guid OperatorId, string? MerchantNumber, string? TerminalNumber) : IRequest; public record RemoveContractFromMerchantCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, Guid ContractId) : IRequest; public record AssignContractToMerchantCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, Guid ContractId) : IRequest; + public record AddMerchantDeviceCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string DeviceIdentifier) : IRequest; + public record SwapMerchantDeviceCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string OldDevice, string NewDevice) : IRequest; } public static class Commands { - public record AddMerchantDeviceCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, string DeviceIdentifier) : IRequest; + public record CreateContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Description, Guid OperatorId) : IRequest; public record CreateMerchantCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Name, string ContactName, string ContactEmail) : 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; public record MakeMerchantDepositCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, decimal Amount, DateTime Date, string Reference) : IRequest; - public record SwapMerchantDeviceCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, string OldDevice, string NewDevice) : IRequest; + 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 744d2be5..33217582 100644 --- a/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs +++ b/EstateManagmentUI.BusinessLogic/Services/TestMediatorService.cs @@ -80,8 +80,8 @@ public Task Send(IRequest request, Cancellation MerchantCommands.RemoveOperatorFromMerchantCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteRemoveOperatorFromMerchant(cmd)), EstateCommands.AddOperatorToEstateCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteAddOperatorToEstate(cmd)), EstateCommands.RemoveOperatorFromEstateCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteRemoveOperatorFromEstate(cmd)), - Commands.AddMerchantDeviceCommand => Task.FromResult((TResponse)(object)Result.Success()), - Commands.SwapMerchantDeviceCommand => Task.FromResult((TResponse)(object)Result.Success()), + MerchantCommands.AddMerchantDeviceCommand => Task.FromResult((TResponse)(object)Result.Success()), + MerchantCommands.SwapMerchantDeviceCommand => Task.FromResult((TResponse)(object)Result.Success()), Commands.CreateMerchantUserCommand => Task.FromResult((TResponse)(object)Result.Success()), Commands.MakeMerchantDepositCommand cmd => Task.FromResult((TResponse)(object)this.ExecuteMakeMerchantDeposit(cmd)),