Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@
@if (assignedDevices == null || !assignedDevices.Any()) {
<p class="text-gray-500 text-center py-8">No devices assigned</p>
}
else {
@* else {
<div class="space-y-2">
@foreach (var device in assignedDevices) {
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
Expand All @@ -334,7 +334,42 @@
</div>
}
</div>
}
} *@
else {
<div class="space-y-2">
@foreach (var device in assignedDevices) {
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center space-x-4">
<span class="font-mono">@device.DeviceIdentifier</span>
</div>

@if (selectedDeviceToSwap == device.DeviceIdentifier) {
<div class="flex items-center space-x-2">
<input @bind="swapDeviceIdentifier" type="text" class="input" placeholder="Enter new device identifier" />
<button type="button" @onclick="() => SwapDeviceConfirm(device.DeviceIdentifier)" class="btn btn-primary">
Confirm
</button>
<button type="button" @onclick="CancelSwapDevice" class="btn btn-secondary">
Cancel
</button>
</div>
}
else {
<div>
<button type="button" @onclick="() => StartSwapDevice(device.DeviceIdentifier)" class="btn btn-secondary">
Swap
</button>
</div>
}
</div>

@if (selectedDeviceToSwap == device.DeviceIdentifier && !string.IsNullOrEmpty(swapDeviceError))
{
<p class="text-red-600 text-sm mt-1">@swapDeviceError</p>
}
}
</div>
}
</div>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Result> 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
Expand All @@ -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;
Expand Down
32 changes: 32 additions & 0 deletions EstateManagmentUI.BusinessLogic/Client/MerchantMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public partial interface IApiClient
Task<Result> AddOperatorToMerchant(MerchantCommands.AddOperatorToMerchantCommand request, CancellationToken cancellationToken);
Task<Result> RemoveContractFromMerchant(MerchantCommands.RemoveContractFromMerchantCommand request, CancellationToken cancellationToken);
Task<Result> AddContractToMerchant(MerchantCommands.AssignContractToMerchantCommand request, CancellationToken cancellationToken);
Task<Result> AddDeviceToMerchant(MerchantCommands.AddMerchantDeviceCommand request, CancellationToken cancellationToken);
Task<Result> SwapMerchantDevice(MerchantCommands.SwapMerchantDeviceCommand request, CancellationToken cancellationToken);
}

public partial class ApiClient : IApiClient {
Expand Down Expand Up @@ -74,6 +76,36 @@ public async Task<Result> AddContractToMerchant(MerchantCommands.AssignContractT
return Result.Success();
}

public async Task<Result> 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<Result> 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<Result> RemoveOperatorFromMerchant(MerchantCommands.RemoveOperatorFromMerchantCommand request,
CancellationToken cancellationToken) {
var token = await this.GetToken(cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ public async Task<Result<List<OperatorModel>>> Handle(EstateQueries.GetAssignedO

public class MerchantRequestHandler : IRequestHandler<MerchantQueries.GetMerchantsQuery, Result<List<MerchantListModel>>>,
IRequestHandler<MerchantQueries.GetMerchantQuery, Result<MerchantModel>>,
IRequestHandler<Commands.AddMerchantDeviceCommand, Result>,
IRequestHandler<MerchantCommands.AddMerchantDeviceCommand, Result>,
IRequestHandler<MerchantCommands.AddOperatorToMerchantCommand, Result>,
IRequestHandler<Commands.CreateMerchantCommand, Result>,
IRequestHandler<Commands.MakeMerchantDepositCommand, Result>,
IRequestHandler<MerchantCommands.RemoveContractFromMerchantCommand, Result>,
IRequestHandler<MerchantCommands.RemoveOperatorFromMerchantCommand, Result>,
IRequestHandler<Commands.SwapMerchantDeviceCommand, Result>,
IRequestHandler<MerchantCommands.SwapMerchantDeviceCommand, Result>,
IRequestHandler<MerchantCommands.UpdateMerchantCommand, Result>,
IRequestHandler<MerchantCommands.AssignContractToMerchantCommand, Result>,
IRequestHandler<MerchantQueries.GetRecentMerchantsQuery, Result<List<RecentMerchantsModel>>>,
Expand All @@ -82,9 +82,9 @@ public async Task<Result<List<MerchantListModel>>> Handle(MerchantQueries.GetMer
return await this.ApiClient.GetMerchants(request, cancellationToken);
}

public async Task<Result> Handle(Commands.AddMerchantDeviceCommand request,
public async Task<Result> Handle(MerchantCommands.AddMerchantDeviceCommand request,
CancellationToken cancellationToken) {
return Result.Success();
return await this.ApiClient.AddDeviceToMerchant(request, cancellationToken);
}

public async Task<Result> Handle(MerchantCommands.AddOperatorToMerchantCommand request,
Expand Down Expand Up @@ -112,9 +112,9 @@ public async Task<Result> Handle(MerchantCommands.RemoveOperatorFromMerchantComm
return await this.ApiClient.RemoveOperatorFromMerchant(request, cancellationToken);
}

public async Task<Result> Handle(Commands.SwapMerchantDeviceCommand request,
public async Task<Result> Handle(MerchantCommands.SwapMerchantDeviceCommand request,
CancellationToken cancellationToken) {
return Result.Success();
return await this.ApiClient.SwapMerchantDevice(request, cancellationToken);
}


Expand Down
6 changes: 4 additions & 2 deletions EstateManagmentUI.BusinessLogic/Requests/Requests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Result>;
public record RemoveContractFromMerchantCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, Guid ContractId) : IRequest<Result>;
public record AssignContractToMerchantCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, Guid ContractId) : IRequest<Result>;
public record AddMerchantDeviceCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string DeviceIdentifier) : IRequest<Result>;
public record SwapMerchantDeviceCommand(CorrelationId CorrelationId, Guid EstateId, Guid MerchantId, string OldDevice, string NewDevice) : IRequest<Result>;
}

public static class Commands
{
public record AddMerchantDeviceCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, string DeviceIdentifier) : IRequest<Result>;

public record CreateContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Description, Guid OperatorId) : IRequest<Result>;
public record CreateMerchantCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Name, string ContactName, string ContactEmail) : IRequest<Result>;
public record CreateMerchantUserCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, string EmailAddress, string Password) : IRequest<Result>;
public record CreateOperatorCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest<Result>;
public record MakeMerchantDepositCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, decimal Amount, DateTime Date, string Reference) : IRequest<Result>;

public record SwapMerchantDeviceCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid MerchantId, string OldDevice, string NewDevice) : IRequest<Result>;

public record UpdateOperatorCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid OperatorId, string Name, bool RequireCustomMerchantNumber, bool RequireCustomTerminalNumber) : IRequest<Result>;
public record AddProductToContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid ContractId, string ProductName, string DisplayText, decimal? Value) : IRequest<Result>;
public record AddTransactionFeeForProductToContractCommand(CorrelationId CorrelationId, string AccessToken, Guid EstateId, Guid ContractId, Guid ProductId, string Description, decimal Value) : IRequest<Result>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ public Task<TResponse> Send<TResponse>(IRequest<TResponse> 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)),

Expand Down
Loading