Skip to content

Commit dda4c15

Browse files
Refactor operator dropdowns to use OperatorDropDownModel
Introduce OperatorDropDownModel for dropdowns and update all UI components, queries, and API methods to use it instead of OperatorModel for selection/filtering. Add new GetOperatorsForDropDownQuery, update factories for conversion, and move full OperatorModel to BusinessLogic.Models. Improves clarity and efficiency in operator selection scenarios.
1 parent 42eaa6d commit dda4c15

18 files changed

Lines changed: 202 additions & 93 deletions

File tree

EstateManagementUI.BlazorServer.Tests/Pages/Estate/EstateIndexPageTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public void EstateIndex_RendersCorrectly()
3535
.ReturnsAsync(Result.Success(new List<RecentContractModel>()));
3636
_mockMediator.Setup(x => x.Send(It.IsAny<EstateQueries.GetAssignedOperatorsQuery>(), default))
3737
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
38-
_mockMediator.Setup(x => x.Send(It.IsAny<OperatorQueries.GetOperatorsQuery>(), default))
39-
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
38+
_mockMediator.Setup(x => x.Send(It.IsAny<OperatorQueries.GetOperatorsForDropDownQuery>(), default))
39+
.ReturnsAsync(Result.Success(new List<OperatorDropDownModel>()));
4040

4141
// Act
4242
var cut = RenderComponent<EstateIndex>();
@@ -65,8 +65,8 @@ public void EstateIndex_DisplaysEstateDetails()
6565
.ReturnsAsync(Result.Success(new List<RecentContractModel>()));
6666
_mockMediator.Setup(x => x.Send(It.IsAny<EstateQueries.GetAssignedOperatorsQuery>(), default))
6767
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
68-
_mockMediator.Setup(x => x.Send(It.IsAny<OperatorQueries.GetOperatorsQuery>(), default))
69-
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
68+
_mockMediator.Setup(x => x.Send(It.IsAny<OperatorQueries.GetOperatorsForDropDownQuery>(), default))
69+
.ReturnsAsync(Result.Success(new List<OperatorDropDownModel>()));
7070

7171
// Act
7272
var cut = RenderComponent<EstateIndex>();
@@ -87,8 +87,8 @@ public void EstateIndex_HasCorrectPageTitle()
8787
.ReturnsAsync(Result.Success(new List<RecentContractModel>()));
8888
_mockMediator.Setup(x => x.Send(It.IsAny<EstateQueries.GetAssignedOperatorsQuery>(), default))
8989
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
90-
_mockMediator.Setup(x => x.Send(It.IsAny<OperatorQueries.GetOperatorsQuery>(), default))
91-
.ReturnsAsync(Result.Success(new List<OperatorModel>()));
90+
_mockMediator.Setup(x => x.Send(It.IsAny<OperatorQueries.GetOperatorsForDropDownQuery>(), default))
91+
.ReturnsAsync(Result.Success(new List<OperatorDropDownModel>()));
9292

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

EstateManagementUI.BlazorServer/Components/Pages/Contracts/Edit.razor

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,6 @@
1111

1212
<PageTitle>Edit Contract</PageTitle>
1313

14-
@if (!hasPermission)
15-
{
16-
<div class="flex items-center justify-center py-12">
17-
<div class="bg-red-50 border border-red-200 rounded-lg p-6 max-w-md">
18-
<div class="flex items-center space-x-3">
19-
<svg class="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
20-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
21-
</svg>
22-
<div>
23-
<h3 class="text-lg font-semibold text-red-900">Access Denied</h3>
24-
<p class="text-sm text-red-700 mt-1">You don't have permission to edit contracts.</p>
25-
</div>
26-
</div>
27-
<button class="btn btn-secondary mt-4 w-full" @onclick='() => NavigationManager.NavigateTo("/contracts")'>
28-
Back to Contracts
29-
</button>
30-
</div>
31-
</div>
32-
}
33-
else
34-
{
3514
<div class="space-y-6">
3615
@if (isLoading)
3716
{
@@ -415,8 +394,12 @@ else
415394
private string? feeErrorMessage;
416395
private Guid currentProductId;
417396

418-
protected override async Task OnInitializedAsync()
419-
{
397+
398+
protected override async Task OnAfterRenderAsync(bool firstRender) {
399+
if (!firstRender) {
400+
await base.OnAfterRenderAsync(firstRender);
401+
return;
402+
}
420403
await RequirePermission(PermissionSection.Contract, PermissionFunction.Edit);
421404
await LoadContract();
422405
}
@@ -426,7 +409,8 @@ else
426409
try
427410
{
428411
isLoading = true;
429-
var result = await Mediator.Send(new ContractQueries.GetContractQuery(CorrelationIdHelper.New(), Guid.Parse("11111111-1111-1111-1111-111111111111"), ContractId));
412+
Guid estateId = await GetEstateId();
413+
var result = await Mediator.Send(new ContractQueries.GetContractQuery(CorrelationIdHelper.New(), estateId, ContractId));
430414

431415
if (result.IsSuccess && result.Data != null)
432416
{
@@ -442,6 +426,7 @@ else
442426
finally
443427
{
444428
isLoading = false;
429+
StateHasChanged();
445430
}
446431
}
447432

@@ -663,4 +648,3 @@ else
663648
public decimal? FeeValue { get; set; }
664649
}
665650
}
666-
}

EstateManagementUI.BlazorServer/Components/Pages/Contracts/New.razor

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,6 @@
1111

1212
<PageTitle>Create New Contract</PageTitle>
1313

14-
@if (!hasPermission)
15-
{
16-
<div class="flex items-center justify-center py-12">
17-
<div class="bg-red-50 border border-red-200 rounded-lg p-6 max-w-md">
18-
<div class="flex items-center space-x-3">
19-
<svg class="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
20-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
21-
</svg>
22-
<div>
23-
<h3 class="text-lg font-semibold text-red-900">Access Denied</h3>
24-
<p class="text-sm text-red-700 mt-1">You don't have permission to create contracts.</p>
25-
</div>
26-
</div>
27-
<button class="btn btn-secondary mt-4 w-full" @onclick='() => NavigationManager.NavigateTo("/contracts")'>
28-
Back to Contracts
29-
</button>
30-
</div>
31-
</div>
32-
}
33-
else
34-
{
3514
<div class="space-y-6">
3615
<!-- Page Header -->
3716
<div class="flex items-center justify-between">
@@ -83,7 +62,7 @@ else
8362
<option value="">-- Select Operator --</option>
8463
@foreach (var op in operators)
8564
{
86-
<option value="@op.OperatorId">@op.Name</option>
65+
<option value="@op.OperatorId">@op.OperatorName</option>
8766
}
8867
</InputSelect>
8968
<ValidationMessage For="@(() => model.OperatorId)" class="text-red-600 text-sm mt-1" />
@@ -123,20 +102,25 @@ else
123102
private bool isLoadingOperators = true;
124103
private bool hasPermission = false;
125104
private string? errorMessage;
126-
private List<OperatorModel>? operators;
105+
private List<OperatorDropDownModel>? operators;
127106

128-
protected override async Task OnInitializedAsync()
129-
{
107+
protected override async Task OnAfterRenderAsync(bool firstRender) {
108+
if (!firstRender) {
109+
await base.OnAfterRenderAsync(firstRender);
110+
return;
111+
}
130112
await RequirePermission(PermissionSection.Contract, PermissionFunction.Create);
131113
await LoadOperators();
132114
}
133115

116+
134117
private async Task LoadOperators()
135118
{
136119
try
137120
{
138121
isLoadingOperators = true;
139-
var result = await Mediator.Send(new OperatorQueries.GetOperatorsQuery(CorrelationIdHelper.New(), Guid.Parse("11111111-1111-1111-1111-111111111111")));
122+
var estateId = await GetEstateId();
123+
var result = await Mediator.Send(new OperatorQueries.GetOperatorsForDropDownQuery(CorrelationIdHelper.New(), estateId));
140124
if (result.IsSuccess)
141125
{
142126
operators = ModelFactory.ConvertFrom(result.Data);
@@ -145,6 +129,7 @@ else
145129
finally
146130
{
147131
isLoadingOperators = false;
132+
StateHasChanged();
148133
}
149134
}
150135

@@ -202,4 +187,3 @@ else
202187
public string? OperatorId { get; set; }
203188
}
204189
}
205-
}

EstateManagementUI.BlazorServer/Components/Pages/Estate/Index.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@
208208
{
209209
@foreach (var op in availableOperators)
210210
{
211-
<option value="@op.OperatorId">@op.Name</option>
211+
<option value="@op.OperatorId">@op.OperatorName</option>
212212
}
213213
}
214214
</select>

EstateManagementUI.BlazorServer/Components/Pages/Estate/Index.razor.cs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public partial class Index
1414
private bool isLoading = true;
1515
private EstateModel? estate;
1616
private List<RecentMerchantsModel> merchants;
17-
private List<OperatorModel>? availableOperators;
17+
private List<OperatorDropDownModel>? availableOperators;
1818
private List<OperatorModel> assignedOperators = new();
1919
private List<RecentContractModel> contracts;
2020
private string activeTab = "overview";
@@ -54,7 +54,7 @@ private async Task<Result> LoadEstateData(CorrelationId correlationId, Guid esta
5454
Task<Result<List<BusinessLogic.Models.RecentMerchantsModel>>> merchantTask = Mediator.Send(new MerchantQueries.GetRecentMerchantsQuery(correlationId, estateId));
5555
Task<Result<List<BusinessLogic.Models.RecentContractModel>>> contractsTask = Mediator.Send(new ContractQueries.GetRecentContractsQuery(correlationId, estateId));
5656
Task<Result<List<BusinessLogic.Models.OperatorModel>>> assignedOperatorsTask = Mediator.Send(new EstateQueries.GetAssignedOperatorsQuery(correlationId, estateId));
57-
Task<Result<List<BusinessLogic.Models.OperatorModel>>> allOperatorsTask= Mediator.Send(new OperatorQueries.GetOperatorsQuery(correlationId, estateId));
57+
Task<Result<List<BusinessLogic.Models.OperatorDropDownModel>>> allOperatorsTask= Mediator.Send(new OperatorQueries.GetOperatorsForDropDownQuery(correlationId, estateId));
5858

5959
await Task.WhenAll(estateTask, merchantTask, contractsTask, assignedOperatorsTask, allOperatorsTask);
6060

@@ -77,9 +77,17 @@ private async Task<Result> LoadEstateData(CorrelationId correlationId, Guid esta
7777
if (allOperatorsTask.Result.IsFailed)
7878
return ResultHelpers.CreateFailure(allOperatorsTask.Result);
7979

80-
List<OperatorModel> unfiltered = ModelFactory.ConvertFrom(allOperatorsTask.Result.Data);
81-
this.availableOperators = unfiltered.Where(u => this.assignedOperators.Select(a => a.OperatorId).Contains(u.OperatorId) == false).ToList();
82-
80+
List<OperatorDropDownModel> unfiltered = ModelFactory.ConvertFrom(allOperatorsTask.Result.Data);
81+
this.availableOperators = unfiltered
82+
.Where(u => !this.assignedOperators.Any(a => a.OperatorId == u.OperatorId))
83+
.Select(u => new OperatorDropDownModel
84+
{
85+
OperatorId = u.OperatorId,
86+
OperatorName = u.OperatorName
87+
})
88+
.ToList();
89+
90+
8391
return Result.Success();
8492
}
8593

@@ -124,9 +132,18 @@ private async Task AddOperatorToEstate()
124132

125133
// Add to assigned list
126134
var op = availableOperators?.FirstOrDefault(o => o.OperatorId == operatorId);
127-
if (op != null && !assignedOperators.Any(a => a.OperatorId == operatorId))
128-
{
129-
assignedOperators.Add(op);
135+
if (op != null && !assignedOperators.Any(a => a.OperatorId == operatorId)) {
136+
OperatorQueries.GetOperatorQuery query = new OperatorQueries.GetOperatorQuery(CorrelationIdHelper.New(), await this.GetEstateId(), operatorId);
137+
var operatorResult = await Mediator.Send(query);
138+
if (operatorResult.IsFailed)
139+
this.NavigationManager.NavigateToErrorPage();
140+
141+
assignedOperators.Add(new OperatorModel() {
142+
OperatorId = operatorResult.Data.OperatorId,
143+
Name = operatorResult.Data.Name,
144+
RequireCustomMerchantNumber = operatorResult.Data.RequireCustomMerchantNumber,
145+
RequireCustomTerminalNumber = operatorResult.Data.RequireCustomTerminalNumber
146+
});
130147
}
131148
}
132149
else

EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@
193193
<option value="">Select an operator...</option>
194194
@if (availableOperators != null) {
195195
@foreach (var op in availableOperators) {
196-
<option value="@op.OperatorId">@op.Name</option>
196+
<option value="@op.OperatorId">@op.OperatorName</option>
197197
}
198198
}
199199
</select>

EstateManagementUI.BlazorServer/Components/Pages/Merchants/Edit.razor.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public partial class Edit
2929
private MerchantEditModel merchantEditModel = new();
3030

3131
// Operators
32-
private List<OperatorModel>? availableOperators;
32+
private List<OperatorDropDownModel>? availableOperators;
3333
private List<MerchantOperatorModel> assignedOperators = new();
3434
private bool showAddOperator = false;
3535
private string? selectedOperatorId;
@@ -150,7 +150,7 @@ private async Task<Result> LoadOperators() {
150150
var correlationId = new CorrelationId(Guid.NewGuid());
151151
var estateId = await this.GetEstateId();
152152

153-
var result = await Mediator.Send(new OperatorQueries.GetOperatorsQuery(correlationId, estateId));
153+
var result = await Mediator.Send(new OperatorQueries.GetOperatorsForDropDownQuery(correlationId, estateId));
154154

155155
if (result.IsFailed) {
156156
return ResultHelpers.CreateFailure(result);
@@ -250,7 +250,7 @@ private async Task SaveAllChanges()
250250
}
251251
}
252252

253-
private void OnOperatorSelected()
253+
private async Task OnOperatorSelected()
254254
{
255255
if (string.IsNullOrEmpty(selectedOperatorId))
256256
{
@@ -263,7 +263,12 @@ private void OnOperatorSelected()
263263
else
264264
{
265265
var operatorId = Guid.Parse(selectedOperatorId);
266-
selectedOperator = availableOperators?.FirstOrDefault(o => o.OperatorId == operatorId);
266+
OperatorQueries.GetOperatorQuery query = new OperatorQueries.GetOperatorQuery(CorrelationIdHelper.New(), await this.GetEstateId(), operatorId);
267+
var getOperatorResult = await this.Mediator.Send(query);
268+
if (getOperatorResult.IsFailed)
269+
NavigationManager.NavigateToErrorPage();
270+
271+
selectedOperator = ModelFactory.ConvertFrom(getOperatorResult.Data);
267272
merchantNumber = null;
268273
terminalNumber = null;
269274
merchantNumberError = null;
@@ -357,7 +362,7 @@ private async Task AddOperatorToMerchant()
357362
{
358363
assignedOperators.Add(new MerchantOperatorModel() {
359364
OperatorId = op.OperatorId,
360-
OperatorName = op.Name
365+
OperatorName = op.OperatorName,
361366
});
362367
}
363368
}

EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionDetail.razor

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
@using ContractProductModel = EstateManagementUI.BlazorServer.Models.ContractProductModel
99
@using MerchantDropDownModel = EstateManagementUI.BlazorServer.Models.MerchantDropDownModel
1010
@using MerchantModel = EstateManagementUI.BlazorServer.Models.MerchantModel
11+
@using OperatorDropDownModel = EstateManagementUI.BlazorServer.Models.OperatorDropDownModel
1112
@using OperatorModel = EstateManagementUI.BlazorServer.Models.OperatorModel
1213
@using TransactionDetailModel = EstateManagementUI.BlazorServer.Models.TransactionDetailModel
1314
@inject IMediator Mediator
@@ -91,12 +92,12 @@
9192
<!-- Operator Filter -->
9293
<div>
9394
<label class="block text-sm font-medium text-gray-700 mb-2">Operator</label>
94-
<MultiSelectDropdown TItem="OperatorModel"
95+
<MultiSelectDropdown TItem="OperatorDropDownModel"
9596
Items="operators"
9697
SelectedItems="_selectedOperatorIds"
9798
SelectedItemsChanged="OnOperatorSelectionChanged"
9899
GetItemId="o => o.OperatorId.ToString()"
99-
GetItemText="o => o.Name ?? string.Empty"
100+
GetItemText="o => o.OperatorName ?? string.Empty"
100101
Placeholder="All Operators"
101102
AriaLabel="Select one or more operators" />
102103
</div>
@@ -338,7 +339,7 @@
338339
// Data
339340
private List<TransactionDetailModel>? detailData;
340341
private List<MerchantDropDownModel>? merchants;
341-
private List<OperatorModel>? operators;
342+
private List<OperatorDropDownModel>? operators;
342343
private List<ContractProductModel>? products;
343344

344345
// KPIs
@@ -433,7 +434,7 @@
433434

434435
// Load filter options
435436
var merchantsTask = Mediator.Send(new MerchantQueries.GetMerchantsForDropDownQuery(correlationId, estateId));
436-
var operatorsTask = Mediator.Send(new OperatorQueries.GetOperatorsQuery(correlationId, estateId));
437+
var operatorsTask = Mediator.Send(new OperatorQueries.GetOperatorsForDropDownQuery(correlationId, estateId));
437438
var contractsTask = Mediator.Send(new ContractQueries.GetContractsQuery(correlationId, estateId));
438439

439440
await Task.WhenAll(merchantsTask, operatorsTask, contractsTask);

EstateManagementUI.BlazorServer/Components/Pages/Reporting/TransactionSummaryMerchant.razor

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
@using EstateManagementUI.BusinessLogic.Requests
55
@using MerchantDropDownModel = EstateManagementUI.BlazorServer.Models.MerchantDropDownModel
66
@using MerchantTransactionSummaryModel = EstateManagementUI.BlazorServer.Models.MerchantTransactionSummaryModel
7+
@using OperatorDropDownModel = EstateManagementUI.BlazorServer.Models.OperatorDropDownModel
78
@using OperatorModel = EstateManagementUI.BlazorServer.Models.OperatorModel
89
@rendermode InteractiveServer
910
@inject IMediator Mediator
@@ -94,7 +95,7 @@
9495
{
9596
@foreach (var op in operators)
9697
{
97-
<option value="@op.OperatorId">@op.Name</option>
98+
<option value="@op.OperatorId">@op.OperatorName</option>
9899
}
99100
}
100101
</select>
@@ -250,7 +251,7 @@
250251
// Data
251252
private List<MerchantTransactionSummaryModel>? summaryData;
252253
private List<MerchantDropDownModel>? merchants;
253-
private List<OperatorModel>? operators;
254+
private List<OperatorDropDownModel>? operators;
254255

255256
// KPIs
256257
private int totalMerchants = 0;
@@ -277,7 +278,7 @@
277278

278279
// Load filter options
279280
var merchantsTask = Mediator.Send(new MerchantQueries.GetMerchantsForDropDownQuery(correlationId, estateId));
280-
var operatorsTask = Mediator.Send(new OperatorQueries.GetOperatorsQuery(correlationId, estateId));
281+
var operatorsTask = Mediator.Send(new OperatorQueries.GetOperatorsForDropDownQuery(correlationId, estateId));
281282

282283
await Task.WhenAll(merchantsTask, operatorsTask);
283284

0 commit comments

Comments
 (0)