From 5ffe9793e8cc5a015e6ec5d9a67f53efd93f0176 Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Sat, 13 Jun 2026 21:50:29 +0200 Subject: [PATCH 1/4] Stable payfast interaction --- .../Components/Pages/Checkout.razor | 12 +- .../Components/Pages/Checkout.razor.cs | 135 ++++++++++++++++-- .../Components/Pages/PaymentFailed.razor | 41 ++++++ ...onfirmation.razor => PaymentSuccess.razor} | 4 +- MidrandBookshop/MidrandBookshop.csproj | 8 +- MidrandBookshop/Program.cs | 6 +- MidrandBookshop/appsettings.json | 15 ++ midrandbooks-uat.yml | 48 +++++-- 8 files changed, 238 insertions(+), 31 deletions(-) create mode 100644 MidrandBookshop/Components/Pages/PaymentFailed.razor rename MidrandBookshop/Components/Pages/{PaymentConfirmation.razor => PaymentSuccess.razor} (95%) diff --git a/MidrandBookshop/Components/Pages/Checkout.razor b/MidrandBookshop/Components/Pages/Checkout.razor index 01d8dc6..aea6f69 100644 --- a/MidrandBookshop/Components/Pages/Checkout.razor +++ b/MidrandBookshop/Components/Pages/Checkout.razor @@ -59,8 +59,18 @@ Total Due

R @($"{ShoppingCart.TotalAmount + ShoppingCart.TotalVat + ShippingCost:F2}")

- + + + @if (IsProcessing == true && CheckoutPayload?.Count > 0) + { +
+ @foreach (var field in CheckoutPayload) + { + + } +
+ } \ No newline at end of file diff --git a/MidrandBookshop/Components/Pages/Checkout.razor.cs b/MidrandBookshop/Components/Pages/Checkout.razor.cs index e166799..824661e 100644 --- a/MidrandBookshop/Components/Pages/Checkout.razor.cs +++ b/MidrandBookshop/Components/Pages/Checkout.razor.cs @@ -1,23 +1,39 @@ -using LiteCharms.Features.MidrandBooks.Payments; +using LiteCharms.Features.Api.Configuration; +using LiteCharms.Features.Hasher; +using LiteCharms.Features.MidrandBooks.AuthorBooks; +using LiteCharms.Features.MidrandBooks.Customers; +using LiteCharms.Features.MidrandBooks.Customers.Models; +using LiteCharms.Features.MidrandBooks.Orders; +using LiteCharms.Features.MidrandBooks.Orders.Models; +using LiteCharms.Features.MidrandBooks.Payments; using LiteCharms.Features.MidrandBooks.Payments.Models; +using LiteCharms.Features.MidrandBooks.Products; namespace MidrandBookshop.Components.Pages; -public partial class Checkout(CartService cartService) +public partial class Checkout() { - [Inject] - private AuthenticationStateProvider AuthStateProvider { get; set; } = default!; - - private LiteCharms.Features.MidrandBooks.Payments.Models.Cart ShoppingCart => cartService.ShoppingCart; + [Inject] public HashService HashService { get; set; } = default!; + [Inject] public PaymentService PaymentService { get; set; } = default!; + [Inject] public OrderService OrderService { get; set; } = default!; + [Inject] public BooksService BooksService { get; set; } = default!; + [Inject] public CartService CartService { get; set; } = default!; + [Inject] public PayfastService PayfastService { get; set; } = default!; + [Inject] public CustomerService CustomerService { get; set; } = default!; + [Inject] public ProductService ProductService { get; set; } = default!; + [Inject] public IOptions PayfastOptions { get; set; } = default!; + [Inject] private AuthenticationStateProvider AuthStateProvider { get; set; } = default!; + [Inject] public IJSRuntime JSRuntime { get; set; } = default!; + private Cart ShoppingCart => CartService.ShoppingCart; private AuthenticationState? AuthState { get; set; } - private System.Security.Claims.ClaimsPrincipal? User { get; set; } - private bool IsAuthenticated => User?.Identity?.IsAuthenticated ?? false; + private ClaimsPrincipal? User { get; set; } + private bool IsProcessing { get; set; } private decimal ShippingCost = 0; private bool IsSameAddress = true; - private decimal OrderTotalAmount => ShoppingCart.TotalAmount + ShoppingCart.TotalVat + ShippingCost; + private Dictionary CheckoutPayload { get; set; } = []; protected override async Task OnInitializedAsync() { @@ -25,7 +41,7 @@ public partial class Checkout(CartService cartService) User = AuthState!.User; Navigation.LocationChanged += OnLocationChanged; - cartService.OnCartChanged += CartService_OnCartChanged; + CartService.OnCartChanged += CartService_OnCartChanged; } private async void CartService_OnCartChanged() => await InvokeAsync(StateHasChanged); @@ -38,17 +54,106 @@ public partial class Checkout(CartService cartService) if (peekQuantity < 1) return; - cartService.UpdateQuantity(item.Price!.Id, delta); + CartService.UpdateQuantity(item.Price!.Id, delta); - await cartService.SaveCartToStorageAsync(); + await CartService.SaveCartToStorageAsync(); } private async void RemoveFromCart(CartItem item) { - cartService.RemoveOneItem(item.Price!.Id); + CartService.RemoveOneItem(item.Price!.Id); - await cartService.SaveCartToStorageAsync(); + await CartService.SaveCartToStorageAsync(); } - private void CompletePurchase(MouseEventArgs args) => Navigation.NavigateTo("/payment-confirmation"); + private async Task PayNow(MouseEventArgs args) + { + if (IsProcessing) return; + + try + { + // 1. Instantly disable the button to prevent duplicate click submissions + IsProcessing = true; + StateHasChanged(); // Force Blazor Server to push the disabled state over SignalR immediately + + var customerEmail = User?.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)!.Value!; + + // 2. Create customer if ShoppingCart.CustomerId is null + if (ShoppingCart.CustomerId == null) + { + var existingCustomer = await CustomerService.GetCustomerAsync(customerEmail); + + if (existingCustomer.IsSuccess) + ShoppingCart.CustomerId = existingCustomer.Value.Id; + + if (existingCustomer.IsFailed) + { + var customerCreate = await CustomerService.CreateCustomerAsync(new CreateCustomer { Email = customerEmail }); + + if (customerCreate.IsSuccess) + ShoppingCart.CustomerId = customerCreate.Value; + } + } + + // 3. Create order using shopping cart and assign the ShoppingCart.OrderId + + var order = await OrderService.CreateOrderAsync(ShoppingCart.CustomerId!.Value, new CreateOrder(ShoppingCart.TotalAmount, null)); + List orderItems = []; + + foreach (var item in ShoppingCart.Items) + { + var bookRequest = await BooksService.GetBookByProductIdAsync(item.Price!.Id); + + if (bookRequest.IsSuccess) + { + var orderItem = new CreateOrderItem(bookRequest.Value.Id, item.Price.Id, item.Quantity); + orderItems.Add(orderItem); + } + } + + var paymentGen = await PaymentService.CreatePaymentAsync(ShoppingCart.TotalAmount, order.Value, HashService.HashEncodeLongId(order.Value).Value); + var merchantPaymentId = HashService.HashEncodeLongId(order.Value).Value; + + await PaymentService.WriteLedgerEntryAsync(new CreateLedgerEntry + { + OrderId = order.Value, + CustomerId = ShoppingCart.CustomerId.Value, + PaymentGatewayId = 1, + PaymentGatewayReference = merchantPaymentId, + PaymentId = paymentGen.Value, + Status = LiteCharms.Features.LedgerStatuses.Sent, + }); + + var addItemsResult = await OrderService.AddItemsToOrderAsync(order.Value, [.. orderItems]); + + // 4. Generate the signed Payfast form payload using your backend service + var hostAddress = "https://localhost:7021"; + + CheckoutPayload = new Dictionary + { + { "merchant_id", PayfastOptions.Value.MerchantId! }, + { "merchant_key", PayfastOptions.Value.MerchantKey! }, + { "return_url", $"{hostAddress}/payment-success" }, + { "cancel_url", $"{hostAddress}/payment-failed" }, + { "notify_url", "https://api.uat.midrandbooks.co.za/v1/payments/payfast/confirm" }, + { "email_address", customerEmail }, + { "m_payment_id", merchantPaymentId }, + { "amount", ShoppingCart.TotalAmount.ToString("F2", CultureInfo.InvariantCulture) }, + { "item_name", "MidrandBooks Sale" }, + }; + + var signature = PayfastService.GenerateSignature(CheckoutPayload!, PayfastOptions.Value.Passphrase).Value; + CheckoutPayload.Add("signature", signature); + + StateHasChanged(); + + // 6. Execute programmatic submit directly into the sandbox + await JSRuntime.InvokeVoidAsync("eval", "document.getElementById('payfastForm').submit();"); + } + catch + { + IsProcessing = false; + StateHasChanged(); + } + } } diff --git a/MidrandBookshop/Components/Pages/PaymentFailed.razor b/MidrandBookshop/Components/Pages/PaymentFailed.razor new file mode 100644 index 0000000..4750825 --- /dev/null +++ b/MidrandBookshop/Components/Pages/PaymentFailed.razor @@ -0,0 +1,41 @@ +@page "/payment-failed" +@rendermode InteractiveServer +@attribute [Authorize] + +
+
+
+
+
+ + + + + +
+

Payment Failed

+

We couldn't process your transaction. Don't worry, no money was deducted from your account, and your cart items are safe.

+ +
+

Common Causes

+

Insufficient funds, incorrect card details, or a temporary bank gateway timeout.

+
+
+ +
+ Try Again + +
+ +
+ Get Help +
+
+
+ +

If you noticed a charge or have any order questions, please contact our support desk with your account email user@email.com.

+
+
+
\ No newline at end of file diff --git a/MidrandBookshop/Components/Pages/PaymentConfirmation.razor b/MidrandBookshop/Components/Pages/PaymentSuccess.razor similarity index 95% rename from MidrandBookshop/Components/Pages/PaymentConfirmation.razor rename to MidrandBookshop/Components/Pages/PaymentSuccess.razor index 0b06630..ebd109d 100644 --- a/MidrandBookshop/Components/Pages/PaymentConfirmation.razor +++ b/MidrandBookshop/Components/Pages/PaymentSuccess.razor @@ -1,4 +1,6 @@ -@page "/payment-confirmation" +@page "/payment-success" +@rendermode InteractiveServer +@attribute [Authorize]
diff --git a/MidrandBookshop/MidrandBookshop.csproj b/MidrandBookshop/MidrandBookshop.csproj index dcbb80e..16e98d4 100644 --- a/MidrandBookshop/MidrandBookshop.csproj +++ b/MidrandBookshop/MidrandBookshop.csproj @@ -18,13 +18,13 @@ - + - + @@ -51,6 +51,10 @@ + + + + diff --git a/MidrandBookshop/Program.cs b/MidrandBookshop/Program.cs index 1172d23..a7d4499 100644 --- a/MidrandBookshop/Program.cs +++ b/MidrandBookshop/Program.cs @@ -1,6 +1,7 @@ using LiteCharms.Features.Extensions; using LiteCharms.Features.Mediator; using LiteCharms.Features.MidrandBooks.Extensions; +using LiteCharms.Features.MidrandBooks.Payments; using Microsoft.AspNetCore.HttpOverrides; using MidrandBookshop.Components; using static LiteCharms.Features.Extensions.Quartz; @@ -25,8 +26,11 @@ builder.Services.AddEmailServices(builder.Configuration); builder.Services.AddEmailServiceBus(); builder.Services.AddHttpClient(); -builder.Services.AddShopServices(); +builder.Services.AddScoped(); +builder.Services.AddShopServices(includeLocalStorage: true); builder.Services.AddHashServices(builder.Configuration); +builder.Services.AddSecurityApiSdk(builder.Configuration); +builder.Services.AddPayfastServices(builder.Configuration); builder.Services.AddMidrandShopDatabase(builder.Configuration); builder.Services.AddMidrandShopPostgresHealthCheck(); diff --git a/MidrandBookshop/appsettings.json b/MidrandBookshop/appsettings.json index 2823623..7d7b09e 100644 --- a/MidrandBookshop/appsettings.json +++ b/MidrandBookshop/appsettings.json @@ -1,7 +1,22 @@ { + "PayfastSettings": { + "CheckoutUrl": "https://sandbox.payfast.co.za/eng/process", + "ValidHosts": [ + "www.payfast.co.za", + "sandbox.payfast.co.za", + "ips.payfast.co.za", + "api.payfast.co.za", + "payment.payfast.io" + ] + }, "LiteCharmsSettings": { "Authority": "https://sts.security.khongisa.co.za" }, + "LiteCharmsClientSettings": { + "Authority": "https://sts.security.khongisa.co.za", + "GrantType": "client_credentials", + "Scope": "midrandbooks-api" + }, "HasherSettings": { "MinHashLength": 11 }, diff --git a/midrandbooks-uat.yml b/midrandbooks-uat.yml index 1ebea6c..0abdaa5 100644 --- a/midrandbooks-uat.yml +++ b/midrandbooks-uat.yml @@ -19,16 +19,18 @@ data: BookshopS3Settings__Region: "garage" BookshopS3Settings__BucketName: "bookshop" BookshopS3Settings__CdnBaseUrl: "https://bookshop.cdn.khongisa.co.za" - ValidPayfastHosts__0: "www.payfast.co.za" - ValidPayfastHosts__1: "sandbox.payfast.co.za" - ValidPayfastHosts__2: "w1w.payfast.co.za" - ValidPayfastHosts__3: "w2w.payfast.co.za" - ValidPayfastHosts__4: "ips.payfast.co.za" - ValidPayfastHosts__5: "api.payfast.co.za" - ValidPayfastHosts__6: "payment.payfast.io" + PayfastSettings__CheckoutUrl: "https://sandbox.payfast.co.za/eng/process" + PayfastSettings__ValidHosts__0: "www.payfast.co.za" + PayfastSettings__ValidHosts__1: "sandbox.payfast.co.za" + PayfastSettings__ValidHosts__2: "ips.payfast.co.za" + PayfastSettings__ValidHosts__3: "api.payfast.co.za" + PayfastSettings__ValidHosts__4: "payment.payfast.io" LiteCharmsSettings__Authority: "https://sts.security.khongisa.co.za" LiteCharmsSettings__Audience: "midrandbooks-api" ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" + LiteCharmsClientSettings__Authority: "https://sts.security.khongisa.co.za" + LiteCharmsClientSettings__GrantType: "client_credentials" + LiteCharmsClientSettings__Scope: "midrandbooks-api" --- apiVersion: v1 kind: Secret @@ -40,12 +42,16 @@ data: connection-string: SG9zdD0xOTIuMTY4LjEuMTcwO0RhdGFiYXNlPW1pZHJhbmRzaG9wLWRldjtVc2VybmFtZT1taWRyYW5kc2hvcC1kZXYtdXNlcjtQYXNzd29yZD1hUFh5a0tnM3RTOWNtRDtQZXJzaXN0IFNlY3VyaXR5IEluZm89VHJ1ZQ== connection-string-quartz: SG9zdD0xOTIuMTY4LjEuMTcwO0RhdGFiYXNlPXNjaGVkdWxlci1kZXY7VXNlcm5hbWU9c2NoZWR1bGVyLWRldi11c2VyO1Bhc3N3b3JkPWtWVm1vV0tKM3h6Z1FYO1BlcnNpc3QgU2VjdXJpdHkgSW5mbz1UcnVl aspire-apikey: bWMzRzYzSzJqNVpPRXNpMEFqTW9qTFRYbTFLRVpGY3R6SUlqU3dEaVRHdXQ4cUdTa1B1V3d4R1AxUmJzY0pVbw== - hasher-salt: VEdsbmFIUWdRMmhoY20xekxDQk5hV1J5WVc1a1FtOXZhM01nYldGclpTQnNiM1J6SUc5bUlHMXZibVY1SUdGdVpDQmhjbVVnWVNCemRXTmpaWE56Wm5Wc0lIWnBjbUZzSUhOMGIzSjVJR2x1SUZOdmRYUm9JRUZtY21sallRPT0= - hasher-payfastpassphrase: OUdBSVIwdFdwaFgwcU8= + hasher-salt: VEdsbmFIUWdRMmhoY20xekxDQk5hV1J5WVc1a1FtOXZhM01nYldGclpTQnNiM1J6SUc5bUlHMXZibVY1SUdGdVpDQmhjbVVnWVNCemRXTmpaWE56Wm5Wc0lIWnBjbUZzSUhOMGIzSjVJR2x1SUZOdmRYUm9JRUZtY21sallRPT0= bookshop-s3-accesskey: R0s1MTRkMmNlOGRjNjkyMzdhMDVjMDFlZWY= bookshop-s3-secretkey: ZWFhZmVkYTFhZWQ0MDllY2ZlNjA3MTRlY2RhNTQ5YjgyYmRmNWEzZGFmOWYxOGRkNjFmNjZiNDk3M2E2NDgyZQ== litecharms-clientid: bWlkcmFuZGJvb2tzLXVhdA== litecharms-clientsecret: c2VjcmV0Xzc3OGJkODM3NWFjNGE3Mzg2N2QxZDdhNjcwODJlZTJjNGU4NmUwODYwYmI0Y2ZlZWI5NDExOTQ5OTk2ZThhOGU= + payfast-passphrase: OUdBSVIwdFdwaFgwcU8= + payfast-merchantid: MTAwNDkzMDc= + payfast-merchantkey: anU2bmF2bjBqY2JmMA== + litecharms-client-clientid: bWlkcmFuZGJvb2tzLWFwaS1zY2FsZXItdWF0 + litecharms-client-clientsecret: c2VjcmV0XzBhOGRjMWY5OTA2MTU5MGE1MmIxMjcyZGIzYTE4NzFkMjc2MWM3OWZiZDA1OGIyYTk2ODkxMTAyOWU0YjIwOGE= --- apiVersion: v1 kind: PersistentVolumeClaim @@ -123,11 +129,31 @@ spec: secretKeyRef: name: midrandbooks-secrets key: hasher-salt - - name: HasherSettings__PayfastPassphrase + - name: PayfastSettings__Passphrase valueFrom: secretKeyRef: name: midrandbooks-secrets - key: hasher-payfastpassphrase + key: payfast-passphrase + - name: PayfastSettings__MerchantId + valueFrom: + secretKeyRef: + name: midrandbooks-secrets + key: payfast-merchantid + - name: PayfastSettings__MerchantKey + valueFrom: + secretKeyRef: + name: midrandbooks-secrets + key: payfast-merchantkey + - name: LiteCharmsClientSettings__ClientId + valueFrom: + secretKeyRef: + name: midrandbooks-secrets + key: litecharms-client-clientid + - name: LiteCharmsClientSettings__ClientSecret + valueFrom: + secretKeyRef: + name: midrandbooks-secrets + key: litecharms-client-clientsecret - name: ConnectionStrings__PostgresScheduler valueFrom: secretKeyRef: -- 2.47.3 From 6d76442dcf45885529ac5969a8f0eea77c4fd738 Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Sat, 13 Jun 2026 21:54:15 +0200 Subject: [PATCH 2/4] Reordered solution --- MidrandBooks.slnx | 1 + 1 file changed, 1 insertion(+) diff --git a/MidrandBooks.slnx b/MidrandBooks.slnx index c9c4a0f..c108294 100644 --- a/MidrandBooks.slnx +++ b/MidrandBooks.slnx @@ -1,6 +1,7 @@ + -- 2.47.3 From ff826f0b73abb0dd7795a662aada14ea398d183c Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Sat, 13 Jun 2026 22:14:21 +0200 Subject: [PATCH 3/4] Moved RedirectToLogin code to code behind --- MidrandBookshop/Components/BookCard.razor | 12 ------------ MidrandBookshop/Components/BookCard.razor.cs | 14 ++++++++++++++ MidrandBookshop/Components/RedirectToLogin.razor | 9 --------- .../Components/RedirectToLogin.razor.cs | 11 +++++++++++ 4 files changed, 25 insertions(+), 21 deletions(-) create mode 100644 MidrandBookshop/Components/BookCard.razor.cs create mode 100644 MidrandBookshop/Components/RedirectToLogin.razor.cs diff --git a/MidrandBookshop/Components/BookCard.razor b/MidrandBookshop/Components/BookCard.razor index d28ae15..4b7591f 100644 --- a/MidrandBookshop/Components/BookCard.razor +++ b/MidrandBookshop/Components/BookCard.razor @@ -50,15 +50,3 @@
- -@code { - [Parameter] public long Id { get; set; } - [Parameter] public string Title { get; set; } = string.Empty; - [Parameter] public string Author { get; set; } = string.Empty; - [Parameter] public decimal Price { get; set; } - [Parameter] public string Category { get; set; } = string.Empty; - [Parameter] public bool IsNew { get; set; } - [Parameter] public string BookImageUrl { get; set; } = string.Empty; - - [Parameter] public EventCallback OnCardClick { get; set; } -} \ No newline at end of file diff --git a/MidrandBookshop/Components/BookCard.razor.cs b/MidrandBookshop/Components/BookCard.razor.cs new file mode 100644 index 0000000..0d90da3 --- /dev/null +++ b/MidrandBookshop/Components/BookCard.razor.cs @@ -0,0 +1,14 @@ +namespace MidrandBookshop.Components; + +public partial class BookCard +{ + [Parameter] public long Id { get; set; } + [Parameter] public string Title { get; set; } = string.Empty; + [Parameter] public string Author { get; set; } = string.Empty; + [Parameter] public decimal Price { get; set; } + [Parameter] public string Category { get; set; } = string.Empty; + [Parameter] public bool IsNew { get; set; } + [Parameter] public string BookImageUrl { get; set; } = string.Empty; + + [Parameter] public EventCallback OnCardClick { get; set; } +} diff --git a/MidrandBookshop/Components/RedirectToLogin.razor b/MidrandBookshop/Components/RedirectToLogin.razor index 98fbb0e..bb7727a 100644 --- a/MidrandBookshop/Components/RedirectToLogin.razor +++ b/MidrandBookshop/Components/RedirectToLogin.razor @@ -31,12 +31,3 @@ - -@code { - protected override void OnInitialized() - { - var returnUrl = Navigation.ToBaseRelativePath(Navigation.Uri); - - Navigation.NavigateTo($"/login?returnUrl={Uri.EscapeDataString(returnUrl)}", forceLoad: true); - } -} \ No newline at end of file diff --git a/MidrandBookshop/Components/RedirectToLogin.razor.cs b/MidrandBookshop/Components/RedirectToLogin.razor.cs new file mode 100644 index 0000000..5598726 --- /dev/null +++ b/MidrandBookshop/Components/RedirectToLogin.razor.cs @@ -0,0 +1,11 @@ +namespace MidrandBookshop.Components; + +public partial class RedirectToLogin +{ + protected override void OnInitialized() + { + var returnUrl = Navigation.ToBaseRelativePath(Navigation.Uri); + + Navigation.NavigateTo($"/login?returnUrl={Uri.EscapeDataString(returnUrl)}", forceLoad: true); + } +} -- 2.47.3 From ec4c9d96890eb4e8092b580787b20b7f0888b517 Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Sat, 13 Jun 2026 23:20:02 +0200 Subject: [PATCH 4/4] Fixed login and logout redirect issue --- MidrandBookshop/Components/Pages/Checkout.razor.cs | 4 ++-- MidrandBookshop/Components/RedirectToLogin.razor.cs | 5 +++-- MidrandBookshop/MidrandBookshop.csproj | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/MidrandBookshop/Components/Pages/Checkout.razor.cs b/MidrandBookshop/Components/Pages/Checkout.razor.cs index 824661e..1316149 100644 --- a/MidrandBookshop/Components/Pages/Checkout.razor.cs +++ b/MidrandBookshop/Components/Pages/Checkout.razor.cs @@ -126,8 +126,8 @@ public partial class Checkout() var addItemsResult = await OrderService.AddItemsToOrderAsync(order.Value, [.. orderItems]); - // 4. Generate the signed Payfast form payload using your backend service - var hostAddress = "https://localhost:7021"; + // 4. Generate the signed Payfast form payload using your backend service + var hostAddress = Navigation.BaseUri.TrimEnd('/'); CheckoutPayload = new Dictionary { diff --git a/MidrandBookshop/Components/RedirectToLogin.razor.cs b/MidrandBookshop/Components/RedirectToLogin.razor.cs index 5598726..1f091b5 100644 --- a/MidrandBookshop/Components/RedirectToLogin.razor.cs +++ b/MidrandBookshop/Components/RedirectToLogin.razor.cs @@ -4,8 +4,9 @@ public partial class RedirectToLogin { protected override void OnInitialized() { - var returnUrl = Navigation.ToBaseRelativePath(Navigation.Uri); + var relativePath = Navigation.ToBaseRelativePath(Navigation.Uri); + var sanitizedRedirectPath = relativePath.StartsWith('/') ? relativePath : $"/{relativePath}"; - Navigation.NavigateTo($"/login?returnUrl={Uri.EscapeDataString(returnUrl)}", forceLoad: true); + Navigation.NavigateTo($"/login?redirectUri={Uri.EscapeDataString(sanitizedRedirectPath)}", forceLoad: true); } } diff --git a/MidrandBookshop/MidrandBookshop.csproj b/MidrandBookshop/MidrandBookshop.csproj index 16e98d4..c0253fb 100644 --- a/MidrandBookshop/MidrandBookshop.csproj +++ b/MidrandBookshop/MidrandBookshop.csproj @@ -18,13 +18,13 @@ - + - + -- 2.47.3