using Microsoft.AspNetCore.Components.Routing; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.WebUtilities; namespace MidrandBookshop.Components.Layout; public partial class MainLayout : IDisposable { 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; private List CartItems = new() { new CartItem { Id = 1, Title = "Letters from M/M (Paris)", Author = "M/M Paris", Price = 720, Quantity = 1 }, new CartItem { Id = 2, Title = "Daan Paans: Floating Signifiers", Author = "Daan Paans", Price = 540, Quantity = 1 }, new CartItem { Id = 3, Title = "Album Architectures, Maputo", Author = "Guedes Archive", Price = 350, Quantity = 1 } }; private void TriggerHeaderLogout() { // Force tear-down of the active client websocket pipeline safely Navigation.NavigateTo("/logout", forceLoad: true); } protected override void OnInitialized() { Navigation.LocationChanged += OnLocationChanged; SyncSearchQueryFromUrl(); } 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 void ChangeQuantity(CartItem item, int delta) { item.Quantity += delta; if (item.Quantity <= 0) { CartItems.Remove(item); } } private void RemoveFromCart(CartItem item) => CartItems.Remove(item); private int GetCartTotal() => CartItems.Sum(item => item.Price * item.Quantity); private void RedirectToCart() { IsCartOpen = false; Navigation.NavigateTo("/cart"); } private void RedirectToCheckout() { IsCartOpen = false; Navigation.NavigateTo("/checkout"); } public void Dispose() { Navigation.LocationChanged -= OnLocationChanged; } public class CartItem { public int Id { get; set; } public string Title { get; set; } = string.Empty; public string Author { get; set; } = string.Empty; public int Price { get; set; } public int Quantity { get; set; } } }