Implemented cart service with state tracker and linked to main layout
continuous-integration/drone/pr Build is passing

This commit is contained in:
Khwezi Mngoma
2026-06-09 23:39:49 +02:00
parent d3e9b30be5
commit 3bce80c963
10 changed files with 326 additions and 92 deletions
@@ -1,11 +1,19 @@
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.WebUtilities;
using MidrandBookshop.Services.ShoppingCart;
using MidrandBookshop.Services.ShoppingCart.Models;
namespace MidrandBookshop.Components.Layout;
public partial class MainLayout : IDisposable
public partial class MainLayout(CartService cartService) : IDisposable
{
[Inject]
private AuthenticationStateProvider AuthStateProvider { 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 string SearchInputBuffer { get; set; } = string.Empty;
private string GlobalSearchQuery { get; set; } = string.Empty;
private bool IsSearchActive { get; set; } = false;
@@ -18,19 +26,25 @@ public partial class MainLayout : IDisposable
new CartItem { Id = 3, Title = "Album Architectures, Maputo", Author = "Guedes Archive", Price = 350, Quantity = 1 }
};
private void TriggerHeaderLogout()
protected override async Task OnInitializedAsync()
{
// Force tear-down of the active client websocket pipeline safely
Navigation.NavigateTo("/logout", forceLoad: true);
}
AuthState = await AuthStateProvider.GetAuthenticationStateAsync();
User = AuthState!.User;
protected override void OnInitialized()
{
Navigation.LocationChanged += OnLocationChanged;
cartService.OnCartChanged += CartService_OnCartChanged;
SyncSearchQueryFromUrl();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await cartService.LoadCartFromStorageAsync();
}
private async void CartService_OnCartChanged() => await InvokeAsync(StateHasChanged);
private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
{
SyncSearchQueryFromUrl();
@@ -107,7 +121,8 @@ public partial class MainLayout : IDisposable
}
private void RemoveFromCart(CartItem item) => CartItems.Remove(item);
private int GetCartTotal() => CartItems.Sum(item => item.Price * item.Quantity);
private decimal GetCartTotal() => ShoppingCart?.TotalPrice ?? 0.00m;
private void RedirectToCart()
{
@@ -124,6 +139,9 @@ public partial class MainLayout : IDisposable
public void Dispose()
{
Navigation.LocationChanged -= OnLocationChanged;
cartService.OnCartChanged -= CartService_OnCartChanged;
GC.SuppressFinalize(this);
}
public class CartItem