using LiteCharms.Features.MidrandBooks.Payments; using LiteCharms.Features.MidrandBooks.Payments.Models; namespace MidrandBookshop.Components.Layout; public partial class MainLayout(CartService cartService) : IDisposable { [Inject] public IToastService ToastService { get; set; } = default!; private Cart ShoppingCart => cartService.ShoppingCart; private string SearchInputBuffer { get; set; } = string.Empty; private string GlobalSearchQuery { get; set; } = string.Empty; private bool IsSearchActive { get; set; } = false; private bool IsCartOpen { get; set; } = false; protected override async Task OnInitializedAsync() { Navigation.LocationChanged += OnLocationChanged; cartService.OnCartChanged += CartService_OnCartChanged; if (cartService.ShoppingCart.Items.Count == 0) await cartService.LoadCartFromStorageAsync(); SyncSearchQueryFromUrl(); } private async void CartService_OnCartChanged() => await InvokeAsync(StateHasChanged); private void OnLocationChanged(object? sender, LocationChangedEventArgs e) { SyncSearchQueryFromUrl(); StateHasChanged(); } private void SyncSearchQueryFromUrl() { var uri = Navigation.ToAbsoluteUri(Navigation.Uri); var queryParameters = QueryHelpers.ParseQuery(uri.Query); if (queryParameters.TryGetValue("q", out var queryVal) && !string.IsNullOrWhiteSpace(queryVal)) { GlobalSearchQuery = queryVal.ToString(); SearchInputBuffer = GlobalSearchQuery; IsSearchActive = true; } else { GlobalSearchQuery = string.Empty; SearchInputBuffer = string.Empty; IsSearchActive = false; } } private void ToggleGlobalSearch() { if (!IsSearchActive) IsSearchActive = true; else CommitSearchNavigation(); } private void HandleSearchKeyDown(KeyboardEventArgs e) { if (e.Key == "Enter") CommitSearchNavigation(); } private void CommitSearchNavigation() { var uri = Navigation.ToAbsoluteUri(Navigation.Uri); var queryParameters = QueryHelpers.ParseQuery(uri.Query); var newRouteParams = new Dictionary(); foreach (var param in queryParameters) { if (param.Key != "q") { newRouteParams[param.Key] = param.Value.ToString(); } } if (!string.IsNullOrWhiteSpace(SearchInputBuffer)) newRouteParams["q"] = SearchInputBuffer.Trim(); else newRouteParams["q"] = null; var baseRoute = uri.AbsolutePath.StartsWith("/product/", StringComparison.OrdinalIgnoreCase) ? "/" : uri.AbsolutePath; var updatedUri = Navigation.GetUriWithQueryParameters(baseRoute, newRouteParams); Navigation.NavigateTo(updatedUri); } private void ToggleCart() => IsCartOpen = !IsCartOpen; private async Task ChangeQuantity(CartItem item, int delta) { var peekQuantity = item.Quantity + delta; if (peekQuantity < 1) return; cartService.UpdateQuantity(item.Price!.Id, delta); await cartService.SaveCartToStorageAsync(); } private async Task RemoveFromCart(CartItem item) { cartService.RemoveOneItem(item.Price!.Id); await cartService.SaveCartToStorageAsync(); ToastService.ShowSuccess($"Removed {item.Product!.Name} from cart", "Cart Changed"); } private decimal GetCartTotal() => ShoppingCart?.TotalAmount ?? 0.00m; private async Task RedirectToCart() { IsCartOpen = false; await cartService.SaveCartToStorageAsync(); Navigation.NavigateTo("/cart"); } private async Task RedirectToCheckout() { IsCartOpen = false; await cartService.SaveCartToStorageAsync(); Navigation.NavigateTo("/checkout", forceLoad: true); } private async Task RedirectToAccount() { IsCartOpen = false; await cartService.SaveCartToStorageAsync(); Navigation.NavigateTo("/account", forceLoad: true); } private async Task HandleLogin() { IsCartOpen = false; await cartService.SaveCartToStorageAsync(); Navigation.NavigateTo("/login", forceLoad: true); } private async Task HandleLogout() { IsCartOpen = false; await cartService.SaveCartToStorageAsync(); Navigation.NavigateTo("/logout", forceLoad: true); } public void Dispose() { Navigation.LocationChanged -= OnLocationChanged; cartService.OnCartChanged -= CartService_OnCartChanged; GC.SuppressFinalize(this); } }