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
47 changes: 0 additions & 47 deletions .github/workflows/prlinked.yml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,23 @@ public void Deposit_MakeDepositButton_ShowsErrorOnFailure()
timeout: TimeSpan.FromSeconds(5));
}

[Fact]
public void Deposit_HasTwoCancelButtons()
{
// Arrange
SetupSuccessfulMerchantLoad();

// Act
IRenderedComponent<MerchantsDeposit> cut = RenderComponent<MerchantsDeposit>(parameters =>
parameters.Add(p => p.MerchantId, _testMerchantId));
cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5));

// Assert - there should be exactly 2 Cancel buttons
IRefreshableElementCollection<IElement> allButtons = cut.FindAll("button");
List<IElement> cancelButtonList = allButtons.Where(b => b.TextContent.Trim() == "Cancel").ToList();
cancelButtonList.Count.ShouldBe(2);
}

[Fact]
public void Deposit_CancelButton_NavigatesToMerchantsIndex()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ public void MerchantsIndex_EditButton_NavigatesToEditMerchantPage()
}

[Fact]
public void MerchantsIndex_MakeDepositButton_NavigatesToDepositPage()
public void MerchantsIndex_MakeDepositButton_OpensDepositModal()
{
// Arrange
var merchantId = Guid.NewGuid();
Expand All @@ -434,15 +434,202 @@ public void MerchantsIndex_MakeDepositButton_NavigatesToDepositPage()
It.IsAny<String>()))
.ReturnsAsync(Result.Success(merchants));

this.MerchantUIService.Setup(m => m.GetMerchant(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), merchantId))
.ReturnsAsync(Result.Success(new MerchantModels.MerchantModel
{
MerchantId = merchantId,
MerchantName = "Test Merchant"
}));

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

// Act - Find and click the Make Deposit button
var makeDepositButton = cut.Find("#makeDepositLink");
makeDepositButton.Click();

// Assert
_fakeNavigationManager.Uri.ShouldContain($"/merchants/{merchantId}/deposit");
// Assert - modal is shown with the deposit form
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Make Merchant Deposit"), TimeSpan.FromSeconds(5));
cut.Markup.ShouldContain("depositAmount");
cut.Markup.ShouldContain("depositDate");
cut.Markup.ShouldContain("depositReference");
}

[Fact]
public void MerchantsIndex_DepositModal_HasOneCancelButton()
{
// Arrange
var merchantId = Guid.NewGuid();
var merchants = new List<MerchantModels.MerchantListModel>
{
new()
{
MerchantId = merchantId,
MerchantName = "Test Merchant",
MerchantReference = "REF001"
}
};

this.MerchantUIService.Setup(m => m.GetMerchants(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<String>(),
It.IsAny<String>(),
It.IsAny<Int32>(),
It.IsAny<String>(),
It.IsAny<String>()))
.ReturnsAsync(Result.Success(merchants));

this.MerchantUIService.Setup(m => m.GetMerchant(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), merchantId))
.ReturnsAsync(Result.Success(new MerchantModels.MerchantModel
{
MerchantId = merchantId,
MerchantName = "Test Merchant"
}));

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

// Open modal
cut.Find("#makeDepositLink").Click();
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Make Merchant Deposit"), TimeSpan.FromSeconds(5));

// Assert - exactly 1 Cancel button in the modal footer
var allButtons = cut.FindAll("button");
var cancelButtons = allButtons.Where(b => b.TextContent.Trim() == "Cancel").ToList();
cancelButtons.Count.ShouldBe(1);
}

[Fact]
public void MerchantsIndex_DepositModal_CancelButton_ClosesModal()
{
// Arrange
var merchantId = Guid.NewGuid();
var merchants = new List<MerchantModels.MerchantListModel>
{
new()
{
MerchantId = merchantId,
MerchantName = "Test Merchant",
MerchantReference = "REF001"
}
};

this.MerchantUIService.Setup(m => m.GetMerchants(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<String>(),
It.IsAny<String>(),
It.IsAny<Int32>(),
It.IsAny<String>(),
It.IsAny<String>()))
.ReturnsAsync(Result.Success(merchants));

this.MerchantUIService.Setup(m => m.GetMerchant(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), merchantId))
.ReturnsAsync(Result.Success(new MerchantModels.MerchantModel
{
MerchantId = merchantId,
MerchantName = "Test Merchant"
}));

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

cut.Find("#makeDepositLink").Click();
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Make Merchant Deposit"), TimeSpan.FromSeconds(5));

// Act - click Cancel
var cancelButton = cut.FindAll("button").FirstOrDefault(b => b.TextContent.Trim() == "Cancel");
cancelButton?.Click();

// Assert - modal is closed
cut.WaitForAssertion(() => cut.Markup.ShouldNotContain("depositAmount"), TimeSpan.FromSeconds(5));
_fakeNavigationManager.Uri.ShouldNotContain("/deposit");
}

[Fact]
public void MerchantsIndex_DepositModal_Submit_ShowsSuccess()
{
// Arrange
var merchantId = Guid.NewGuid();
var merchants = new List<MerchantModels.MerchantListModel>
{
new()
{
MerchantId = merchantId,
MerchantName = "Test Merchant",
MerchantReference = "REF001"
}
};

this.MerchantUIService.Setup(m => m.GetMerchants(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<String>(),
It.IsAny<String>(),
It.IsAny<Int32>(),
It.IsAny<String>(),
It.IsAny<String>()))
.ReturnsAsync(Result.Success(merchants));

this.MerchantUIService.Setup(m => m.GetMerchant(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), merchantId))
.ReturnsAsync(Result.Success(new MerchantModels.MerchantModel
{
MerchantId = merchantId,
MerchantName = "Test Merchant"
}));

this.MerchantUIService.Setup(m => m.MakeMerchantDeposit(
It.IsAny<CorrelationId>(),
It.IsAny<Guid>(),
merchantId,
It.IsAny<MerchantModels.DepositModel>()))
.ReturnsAsync(Result.Success);

var cut = RenderComponent<MerchantsIndex>();
cut.Instance.SetDelayOverride(500);
cut.WaitForState(() => !cut.Markup.Contains("animate-spin"), TimeSpan.FromSeconds(5));

cut.Find("#makeDepositLink").Click();
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Make Merchant Deposit"), TimeSpan.FromSeconds(5));

// Act - fill and submit form
cut.Find("#depositAmount").Change(100);
cut.Find("#depositDate").Change(DateTime.Today.ToString("yyyy-MM-dd"));
cut.Find("#depositReference").Change("TEST-REF-001");
cut.Find("#makeDepositButton").Click();

// Assert - success message is shown before modal closes
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Deposit recorded successfully"), TimeSpan.FromSeconds(5));
cut.WaitForAssertion(() => cut.Markup.ShouldNotContain("depositAmount"), TimeSpan.FromSeconds(5));
}

[Fact]
public void MerchantsIndex_DepositModal_OpensWithoutMerchantName_WhenGetMerchantFails()
{
// Arrange
var merchantId = Guid.NewGuid();
var merchants = new List<MerchantModels.MerchantListModel>
{
new()
{
MerchantId = merchantId,
MerchantName = "Test Merchant",
MerchantReference = "REF001"
}
};

this.MerchantUIService.Setup(m => m.GetMerchants(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), It.IsAny<String>(),
It.IsAny<String>(),
It.IsAny<Int32>(),
It.IsAny<String>(),
It.IsAny<String>()))
.ReturnsAsync(Result.Success(merchants));

this.MerchantUIService.Setup(m => m.GetMerchant(It.IsAny<CorrelationId>(), It.IsAny<Guid>(), merchantId))
.ReturnsAsync(Result.Failure());

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

// Act - click Make Deposit when GetMerchant fails
cut.Find("#makeDepositLink").Click();

// Assert - modal opens but without merchant name
cut.WaitForAssertion(() => cut.Markup.ShouldContain("Make Merchant Deposit"), TimeSpan.FromSeconds(5));
cut.Markup.ShouldContain("depositAmount");
cut.Markup.ShouldNotContain("For merchant:");
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<label class="block text-sm font-medium text-gray-700 mb-1">
Deposit Amount (£) <span class="text-red-500">*</span>
</label>
<InputNumber @bind-Value="model.Amount" class="input w-full" placeholder="Enter whole pounds only" name="Amount" id="depositAmount" />
<InputNumber @bind-Value="model.Amount" class="input w-1/2" placeholder="Enter whole pounds only" name="Amount" id="depositAmount" />
<ValidationMessage For="@(() => model.Amount)" class="text-red-600 text-sm mt-1" />
<p class="text-sm text-gray-500 mt-1">Please enter whole pounds only (no pence)</p>
</div>
Expand All @@ -60,7 +60,7 @@
<label class="block text-sm font-medium text-gray-700 mb-1">
Date of Deposit <span class="text-red-500">*</span>
</label>
<InputDate @bind-Value="model.Date" class="input w-full" name="Date" id="depositDate" />
<InputDate @bind-Value="model.Date" class="input w-1/2" name="Date" id="depositDate" />
<ValidationMessage For="@(() => model.Date)" class="text-red-600 text-sm mt-1" />
<p class="text-sm text-gray-500 mt-1">Can be in the past for deposit catch-ups, but cannot be in the future</p>
</div>
Expand All @@ -69,7 +69,7 @@
<label class="block text-sm font-medium text-gray-700 mb-1">
Reference <span class="text-red-500">*</span>
</label>
<InputText @bind-Value="model.Reference" class="input w-full" placeholder="Enter deposit reference" name="Reference" id="depositReference" />
<InputText @bind-Value="model.Reference" class="input w-1/2" placeholder="Enter deposit reference" name="Reference" id="depositReference" />
<ValidationMessage For="@(() => model.Reference)" class="text-red-600 text-sm mt-1" />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,84 @@
}
</div>

<!-- Make Deposit Modal -->
@if (showDepositModal)
{
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" @onclick="CloseDepositModal">
<div class="bg-white rounded-lg p-6 max-w-lg w-full mx-4" @onclick:stopPropagation="true">
<div class="mb-4">
<h3 class="text-lg font-semibold text-gray-900">Make Merchant Deposit</h3>
@if (!string.IsNullOrEmpty(depositModalMerchantName))
{
<p class="text-sm text-gray-600 mt-1">For merchant: @depositModalMerchantName</p>
}
</div>

@if (!string.IsNullOrWhiteSpace(depositErrorMessage))
{
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-4">
<p class="font-medium">Error</p>
<p class="text-sm">@depositErrorMessage</p>
</div>
}

@if (!string.IsNullOrWhiteSpace(depositSuccessMessage))
{
<div class="bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-lg mb-4">
<p class="font-medium">Success</p>
<p class="text-sm">@depositSuccessMessage</p>
</div>
}

<EditForm Model="@depositModel" OnValidSubmit="@HandleDepositSubmit">
<DataAnnotationsValidator />

<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
Deposit Amount (£) <span class="text-red-500">*</span>
</label>
<InputNumber @bind-Value="depositModel.Amount" class="input w-1/2" placeholder="Enter whole pounds only" name="Amount" id="depositAmount" />
<ValidationMessage For="@(() => depositModel.Amount)" class="text-red-600 text-sm mt-1" />
<p class="text-sm text-gray-500 mt-1">Please enter whole pounds only (no pence)</p>
</div>

<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
Date of Deposit <span class="text-red-500">*</span>
</label>
<InputDate @bind-Value="depositModel.Date" class="input w-1/2" name="Date" id="depositDate" />
<ValidationMessage For="@(() => depositModel.Date)" class="text-red-600 text-sm mt-1" />
<p class="text-sm text-gray-500 mt-1">Can be in the past for deposit catch-ups, but cannot be in the future</p>
</div>

<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
Reference <span class="text-red-500">*</span>
</label>
<InputText @bind-Value="depositModel.Reference" class="input w-1/2" placeholder="Enter deposit reference" name="Reference" id="depositReference" />
<ValidationMessage For="@(() => depositModel.Reference)" class="text-red-600 text-sm mt-1" />
</div>
</div>

<div class="flex justify-end space-x-4 pt-6 mt-6 border-t">
<button type="button" class="btn btn-secondary" @onclick="CloseDepositModal" disabled="@isDepositSaving">
Cancel
</button>
<button id="makeDepositButton" type="submit" class="btn btn-primary" disabled="@isDepositSaving">
@if (isDepositSaving)
{
<span class="inline-block animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></span>
<span>Processing...</span>
}
else
{
<span>Make Deposit</span>
}
</button>
</div>
</EditForm>
</div>
</div>
}

Loading
Loading