Redesigned account, checkout Added stock management design elements
This commit is contained in:
@@ -5,6 +5,14 @@ using LiteCharms.Features.MidrandBooks.Orders;
|
||||
using LiteCharms.Features.MidrandBooks.Orders.Models;
|
||||
using LiteCharms.Features.MidrandBooks.Payments;
|
||||
using LiteCharms.Features.MidrandBooks.Payments.Models;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Security.Claims;
|
||||
using System.Globalization;
|
||||
using LiteCharms;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
|
||||
namespace MidrandBookshop.Components.Pages;
|
||||
|
||||
@@ -32,6 +40,13 @@ public partial class Checkout()
|
||||
public string? OrderNotes { get; set; }
|
||||
private Dictionary<string, string> CheckoutPayload { get; set; } = [];
|
||||
|
||||
// Tracks available quantities indexed by Price ID
|
||||
protected Dictionary<long, int> AvailableStockMap { get; set; } = [];
|
||||
|
||||
// Quick validation flag to evaluate checkout block state
|
||||
protected bool HasStockExceptions => ShoppingCart.Items.Any(item =>
|
||||
AvailableStockMap.TryGetValue(item.Price!.Id, out var count) && count <= 0);
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||
@@ -41,60 +56,91 @@ public partial class Checkout()
|
||||
CartService.OnCartChanged += CartService_OnCartChanged;
|
||||
|
||||
if (CartService.ShoppingCart.Items.Count == 0)
|
||||
{
|
||||
await CartService.LoadCartFromStorageAsync();
|
||||
}
|
||||
|
||||
await RefreshStockValidationAsync();
|
||||
}
|
||||
|
||||
private async void CartService_OnCartChanged() => await InvokeAsync(StateHasChanged);
|
||||
private async void CartService_OnCartChanged()
|
||||
{
|
||||
await RefreshStockValidationAsync();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private void OnLocationChanged(object? sender, LocationChangedEventArgs e) => StateHasChanged();
|
||||
|
||||
private async Task RefreshStockValidationAsync()
|
||||
{
|
||||
AvailableStockMap.Clear();
|
||||
foreach (var item in ShoppingCart.Items)
|
||||
{
|
||||
if (item.Price is not null)
|
||||
{
|
||||
// Mapped fallback default (set to 0 for specific keys to test stock warnings instantly)
|
||||
// In production: pull from your inventory system:
|
||||
// var stockCheck = await BooksService.GetStockLevelAsync(item.Price.Id);
|
||||
int liveStockAvailable = 1;
|
||||
|
||||
AvailableStockMap[item.Price.Id] = liveStockAvailable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ChangeQuantity(CartItem item, int delta)
|
||||
{
|
||||
var peekQuantity = item.Quantity + delta;
|
||||
|
||||
if (peekQuantity < 1) return;
|
||||
|
||||
CartService.UpdateQuantity(item.Price!.Id, delta);
|
||||
// Block internal counters exceeding live available thresholds
|
||||
if (AvailableStockMap.TryGetValue(item.Price!.Id, out var maxAvailable) && peekQuantity > maxAvailable)
|
||||
{
|
||||
ToastService.ShowWarning($"Cannot exceed remaining stock limit ({maxAvailable} available).", "Stock Limit");
|
||||
return;
|
||||
}
|
||||
|
||||
CartService.UpdateQuantity(item.Price!.Id, delta);
|
||||
await CartService.SaveCartToStorageAsync();
|
||||
}
|
||||
|
||||
private async Task RemoveFromCart(CartItem item)
|
||||
{
|
||||
CartService.RemoveOneItem(item.Price!.Id);
|
||||
|
||||
await CartService.SaveCartToStorageAsync();
|
||||
}
|
||||
|
||||
private async Task PayNow(MouseEventArgs args)
|
||||
{
|
||||
// Fail-safe protection boundary check
|
||||
if (HasStockExceptions)
|
||||
{
|
||||
ToastService.ShowError("Your order cannot contain items that are out of stock.", "Inventory Issue");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsProcessing)
|
||||
{
|
||||
ToastService.ShowWarning("Please wait, completing your payment", "Busy...");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IsProcessing = true;
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
Result<long> orderResult;
|
||||
|
||||
var customerId = (long)ShoppingCart.CustomerId!;
|
||||
|
||||
if (!ShoppingCart.OrderId.HasValue)
|
||||
{
|
||||
CreateOrder request = new(ShoppingCart.TotalAmount, null);
|
||||
|
||||
orderResult = await OrderService.CreateOrderAsync(customerId, request, CancellationToken);
|
||||
ShoppingCart.OrderId = orderResult.Value;
|
||||
}
|
||||
|
||||
List<CreateOrderItem> orderItems = [];
|
||||
|
||||
var orderId = (long)ShoppingCart.OrderId;
|
||||
|
||||
await OrderService.ClearOrderItemsAsync(orderId, CancellationToken);
|
||||
@@ -102,7 +148,6 @@ public partial class Checkout()
|
||||
foreach (var item in ShoppingCart.Items)
|
||||
{
|
||||
var bookRequest = await BooksService.GetBookByProductIdAsync(item.Price!.Id, CancellationToken);
|
||||
|
||||
if (bookRequest.IsSuccess)
|
||||
{
|
||||
var orderItem = new CreateOrderItem(bookRequest.Value.Id, item.Price.Id, item.Quantity);
|
||||
@@ -114,20 +159,17 @@ public partial class Checkout()
|
||||
var paymentGen = await PaymentService.CreatePaymentAsync(ShoppingCart.TotalAmount, orderId, orderHash, CancellationToken);
|
||||
|
||||
long paymentId = 0;
|
||||
|
||||
if (paymentGen.IsSuccess) paymentId = paymentGen.Value;
|
||||
|
||||
if (paymentGen.IsFailed)
|
||||
{
|
||||
var paymentFetch = await PaymentService.GetOrderPaymentAsync(orderId, CancellationToken);
|
||||
|
||||
if (paymentFetch.IsFailed)
|
||||
{
|
||||
ToastService.ShowError("Failed to get fetch your previously made payment", "Payment Check");
|
||||
|
||||
ToastService.ShowError("Failed to fetch your previously made payment", "Payment Check");
|
||||
IsProcessing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
paymentId = paymentFetch.Value.Id;
|
||||
}
|
||||
|
||||
@@ -162,15 +204,13 @@ public partial class Checkout()
|
||||
CheckoutPayload.Add("signature", signature);
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("eval", "document.getElementById('payfastForm').submit();");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ToastService.ShowError($"Failed to perform checkout: {ex.Message}", "Checkout");
|
||||
|
||||
IsProcessing = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user