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 @@ -29,12 +29,10 @@ public void EstateIndex_RendersCorrectly()

_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetEstateQuery>(), default))
.ReturnsAsync(Result.Success(estate));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetMerchantsQuery>(), default))
.ReturnsAsync(Result.Success(new List<MerchantModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetOperatorsQuery>(), default))
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetContractsQuery>(), default))
.ReturnsAsync(Result.Success(new List<ContractModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetRecentMerchantsQuery>(), default))
.ReturnsAsync(Result.Success(new List<RecentMerchantsModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetRecentContractsQuery>(), default))
.ReturnsAsync(Result.Success(new List<RecentContractModel>()));

// Act
var cut = RenderComponent<EstateIndex>();
Expand All @@ -57,18 +55,15 @@ public void EstateIndex_DisplaysEstateDetails()

_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetEstateQuery>(), default))
.ReturnsAsync(Result.Success(estate));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetOperatorsQuery>(), default))
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetContractsQuery>(), default))
.ReturnsAsync(Result.Success(new List<ContractModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetMerchantsQuery>(), default))
.ReturnsAsync(Result.Success(new List<MerchantModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetRecentMerchantsQuery>(), default))
.ReturnsAsync(Result.Success(new List<RecentMerchantsModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetRecentContractsQuery>(), default))
.ReturnsAsync(Result.Success(new List<RecentContractModel>()));

// Act
var cut = RenderComponent<EstateIndex>();
//cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5));


// Assert
//cut.Markup.ShouldContain("Test Estate");
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Test Estate"), timeout: TimeSpan.FromSeconds(5));
}

Expand All @@ -78,13 +73,11 @@ public void EstateIndex_HasCorrectPageTitle()
// Arrange
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetEstateQuery>(), default))
.ReturnsAsync(Result.Success(new EstateModel { EstateId = Guid.NewGuid() }));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetMerchantsQuery>(), default))
.ReturnsAsync(Result.Success(new List<MerchantModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetOperatorsQuery>(), default))
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetContractsQuery>(), default))
.ReturnsAsync(Result.Success(new List<ContractModel>()));

_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetRecentMerchantsQuery>(), default))
.ReturnsAsync(Result.Success(new List<RecentMerchantsModel>()));
_mockMediator.Setup(x => x.Send(It.IsAny<Queries.GetRecentContractsQuery>(), default))
.ReturnsAsync(Result.Success(new List<RecentContractModel>()));

// Act
var cut = RenderComponent<EstateIndex>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600 mb-1">Total Merchants</p>
<p class="text-3xl font-bold text-gray-900">@(merchants?.Count ?? 0)</p>
<p class="text-3xl font-bold text-gray-900">@(estate.Merchants?.Count ?? 0)</p>
</div>
<svg class="w-12 h-12 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
Expand All @@ -74,7 +74,7 @@
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600 mb-1">Total Operators</p>
<p class="text-3xl font-bold text-gray-900">@(assignedOperators?.Count ?? 0)</p>
<p class="text-3xl font-bold text-gray-900">@(estate.Operators?.Count ?? 0)</p>
</div>
<svg class="w-12 h-12 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"></path>
Expand All @@ -86,7 +86,7 @@
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600 mb-1">Total Contracts</p>
<p class="text-3xl font-bold text-gray-900">@(contracts?.Count ?? 0)</p>
<p class="text-3xl font-bold text-gray-900">@(estate.Operators?.Count ?? 0)</p>
</div>
<svg class="w-12 h-12 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
Expand All @@ -98,7 +98,7 @@
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-gray-600 mb-1">Total Users</p>
<p class="text-3xl font-bold text-gray-900">5</p>
<p class="text-3xl font-bold text-gray-900">@(estate.Users?.Count ?? 0)</p>
</div>
<svg class="w-12 h-12 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path>
Expand All @@ -118,12 +118,12 @@
@if (merchants != null && merchants.Any())
{
<div class="space-y-3">
@foreach (var merchant in merchants.Take(5))
@foreach (var merchant in merchants)
{
<div class="flex items-center justify-between p-3 bg-white rounded-lg">
<div>
<p class="font-medium text-gray-900">@merchant.MerchantName</p>
<p class="text-sm text-gray-600">@merchant.MerchantReference</p>
<p class="text-gray-900 font-medium">@merchant.Name (@merchant.Reference)</p>
<p class="text-sm text-gray-500">@merchant.CreatedDateTime.ToString("dd/MM/yyyy HH:mm")</p>
</div>
<a href="/merchants/@merchant.MerchantId" class="text-blue-600 hover:text-blue-800">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using EstateManagementUI.BlazorServer.Permissions;
using EstateManagementUI.BusinessLogic.Requests;
using Microsoft.AspNetCore.Components.Authorization;
using Shared.Results;
using SimpleResults;

namespace EstateManagementUI.BlazorServer.Components.Pages.Estate
Expand All @@ -12,10 +13,10 @@ public partial class Index
{
private bool isLoading = true;
private EstateModel? estate;
private List<MerchantModel>? merchants;
private List<RecentMerchantsModel> merchants;
private List<OperatorModel>? availableOperators;
private List<OperatorModel> assignedOperators = new();
private List<ContractModel>? contracts;
private List<RecentContractModel> contracts;
private string activeTab = "overview";
private bool showAddOperator = false;
private string? selectedOperatorId;
Expand All @@ -35,41 +36,9 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
await RequirePermission(PermissionSection.Estate, PermissionFunction.View);
CorrelationId correlationId = new(Guid.NewGuid());
Guid estateId = await this.GetEstateId();

Result<BusinessLogic.Models.EstateModel> estateResult = await Mediator.Send(new Queries.GetEstateQuery(correlationId, estateId));
if (estateResult.IsSuccess)
{
estate = ModelFactory.ConvertFrom(estateResult.Data);
// Load assigned operators from estate model
if (estate.Operators != null)
{
assignedOperators = estate.Operators.Select(o => new OperatorModel
{
OperatorId = o.OperatorId,
Name = o.Name,
RequireCustomMerchantNumber = o.RequireCustomMerchantNumber,
RequireCustomTerminalNumber = o.RequireCustomTerminalNumber
}).ToList();
}
}

// TODO: Make these calls concurrent...
var merchantsResult = await Mediator.Send(new Queries.GetMerchantsQuery(correlationId, estateId));
if (merchantsResult.IsSuccess)
{
merchants = ModelFactory.ConvertFrom(merchantsResult.Data);
}

var operatorsResult = await Mediator.Send(new Queries.GetOperatorsQuery(correlationId, String.Empty, estateId));
if (operatorsResult.IsSuccess)
{
availableOperators = ModelFactory.ConvertFrom(operatorsResult.Data);
}

var contractsResult = await Mediator.Send(new Queries.GetContractsQuery(correlationId, String.Empty, estateId));
if (contractsResult.IsSuccess)
{
contracts = ModelFactory.ConvertFrom(contractsResult.Data);
var result = await this.LoadEstateData(correlationId, estateId);
if (result.IsFailed) {
this.NavigationManager.NavigateToErrorPage();
}
}
finally
Expand All @@ -79,6 +48,35 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
}
}

private async Task<Result> LoadEstateData(CorrelationId correlationId, Guid estateId)
{
Result<BusinessLogic.Models.EstateModel> estateResult = await Mediator.Send(new Queries.GetEstateQuery(correlationId, estateId));
if (estateResult.IsFailed)
return ResultHelpers.CreateFailure(estateResult);
estate = ModelFactory.ConvertFrom(estateResult.Data);

Result<List<BusinessLogic.Models.RecentMerchantsModel>> merchantResult = await Mediator.Send(new Queries.GetRecentMerchantsQuery(correlationId, estateId));

if (merchantResult.IsFailed)
return ResultHelpers.CreateFailure(merchantResult);

// Note: API returns merchants in creation order (newest first)
// If ordering is incorrect, would need CreatedDate field in the model
this.merchants = ModelFactory.ConvertFrom(merchantResult.Data);

Result<List<BusinessLogic.Models.RecentContractModel>> contractResult = await Mediator.Send(new Queries.GetRecentContractsQuery(correlationId, estateId));

if (contractResult.IsFailed)
return ResultHelpers.CreateFailure(contractResult);

// Note: API returns merchants in creation order (newest first)
// If ordering is incorrect, would need CreatedDate field in the model
this.contracts = ModelFactory.ConvertFrom(contractResult.Data);

return Result.Success();
}


private void SetActiveTab(string tab)
{
activeTab = tab;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@
</div>
<div>
<p class="text-gray-900 font-medium">@merchant.Name (@merchant.Reference)</p>
@* <p class="text-sm text-gray-500">@merchant.Reference</p> *@
<p class="text-sm text-gray-500">@merchant.CreatedDateTime.ToString("dd/MM/yyyy HH:mm")</p>
</div>
</div>
Expand Down
41 changes: 39 additions & 2 deletions EstateManagementUI.BlazorServer/Factories/ModelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,41 @@
namespace EstateManagementUI.BlazorServer.Factories {
public static class ModelFactory {
public static EstateModel ConvertFrom(BusinessLogic.Models.EstateModel model) {
EstateModel result = new EstateModel { EstateId = model.EstateId, EstateName = model.EstateName, Operators = new List<EstateOperatorModel>(), Reference = model.Reference };
EstateModel result = new EstateModel { EstateId = model.EstateId, EstateName = model.EstateName,
Operators = new List<EstateOperatorModel>(),
Contracts = new(),
Merchants = new(),
Users = new(),
Reference = model.Reference };
if (model.Operators != null && model.Operators.Any()) {
model.Operators.ForEach((o) => result.Operators.Add(ConvertFrom(o)));
}
if (model.Merchants != null && model.Merchants.Any()) {
model.Merchants.ForEach((m) => result.Merchants.Add(ConvertFrom(m)));
}
if (model.Contracts != null && model.Contracts.Any()) {
model.Contracts.ForEach((m) => result.Contracts.Add(ConvertFrom(m)));
}
if (model.Users != null && model.Users.Any())
{
model.Users.ForEach((m) => result.Users.Add(ConvertFrom(m)));
}

return result;
}

private static EstateUserModel ConvertFrom(BusinessLogic.Models.EstateUserModel model) {
return new EstateUserModel() { CreatedDateTime = model.CreatedDateTime, EmailAddress = model.EmailAddress, UserId = model.UserId };
}

private static EstateContractModel ConvertFrom(BusinessLogic.Models.EstateContractModel model) {
return new EstateContractModel() { ContractId = model.ContractId, Name = model.Name, OperatorId = model.OperatorId, OperatorName = model.OperatorName };
}

private static EstateMerchantModel ConvertFrom(BusinessLogic.Models.EstateMerchantModel model) {
return new EstateMerchantModel() { Reference = model.Reference, Name = model.Name, MerchantId = model.MerchantId };
}

public static EstateOperatorModel ConvertFrom(BusinessLogic.Models.EstateOperatorModel model) {
return new EstateOperatorModel() { Name = model.Name, OperatorId = model.OperatorId, RequireCustomMerchantNumber = model.RequireCustomMerchantNumber, RequireCustomTerminalNumber = model.RequireCustomTerminalNumber };
}
Expand Down Expand Up @@ -299,7 +326,7 @@ public static List<FileImportLogModel> ConvertFrom(List<BusinessLogic.Models.Fil
return result;
}

public static List<RecentMerchantsModel>? ConvertFrom(List<BusinessLogic.Models.RecentMerchantsModel> models) {
public static List<RecentMerchantsModel> ConvertFrom(List<BusinessLogic.Models.RecentMerchantsModel> models) {
List<RecentMerchantsModel> result = new List<RecentMerchantsModel>();
models.ForEach(m => result.Add(ConvertFrom(m)));
return result;
Expand All @@ -322,5 +349,15 @@ private static RecentMerchantsModel ConvertFrom(BusinessLogic.Models.RecentMerch
};
return result;
}

public static List<RecentContractModel> ConvertFrom(List<BusinessLogic.Models.RecentContractModel> models) {
List<RecentContractModel> result = new List<RecentContractModel>();
models.ForEach(m => result.Add(ConvertFrom(m)));
return result;
}

private static RecentContractModel ConvertFrom(BusinessLogic.Models.RecentContractModel model) {
return new RecentContractModel { OperatorName = model.OperatorName, Description = model.Description, ContractId = model.ContractId };
}
}
}
34 changes: 34 additions & 0 deletions EstateManagementUI.BlazorServer/Models/Models.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ public class EstateModel
public string? EstateName { get; set; }
public string? Reference { get; set; }
public List<EstateOperatorModel>? Operators { get; set; }
public List<EstateMerchantModel>? Merchants { get; set; }
public List<EstateContractModel>? Contracts { get; set; }
public List<EstateUserModel>? Users { get; set; }
}

public class EstateUserModel
{
public Guid UserId { get; set; }
public string? EmailAddress { get; set; }
public DateTime CreatedDateTime { get; set; }
}

public class EstateOperatorModel
Expand All @@ -15,6 +25,23 @@ public class EstateOperatorModel
public string? Name { get; set; }
public bool RequireCustomMerchantNumber { get; set; }
public bool RequireCustomTerminalNumber { get; set; }
public DateTime CreatedDateTime { get; set; }
}

public class EstateContractModel
{
public Guid OperatorId { get; set; }
public Guid ContractId { get; set; }
public string? Name { get; set; }
public string? OperatorName { get; set; }
}


public class EstateMerchantModel
{
public Guid MerchantId { get; set; }
public string? Name { get; set; }
public string? Reference { get; set; }
}

// Merchant Models
Expand Down Expand Up @@ -247,4 +274,11 @@ public class RecentMerchantsModel
public String Reference { get; set; }
public String Region { get; set; }
public String Town { get; set; }
}

public class RecentContractModel
{
public Guid ContractId { get; set; }
public string? Description { get; set; }
public string? OperatorName { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
}
},
"AppSettings": {
"TestMode": "Full"
"TestMode": "Disabled"
}
}
Loading