@page "/voiceworks" @using JSMR.Application.Common.Search @using JSMR.Application.VoiceWorks.Queries.Search @using JSMR.UI.Blazor.Components @using JSMR.UI.Blazor.Filters @using JSMR.UI.Blazor.Services @using Microsoft.AspNetCore.WebUtilities @inject VoiceWorksClient Client @inject IJSRuntime JS @inject NavigationManager NavigationManager @implements IAsyncDisposable; Voice Works

Voice Works

@if (searchResults is not null) { } @code { private bool _isAlive = true; private CancellationTokenSource _cts = new(); VoiceWorkFilterState FilterState = new(); SearchResult? searchResults; protected override async Task OnInitializedAsync() { NavigationManager.LocationChanged += OnLocationChanged; FilterState = VoiceWorkFilterState.FromQuery(new Uri(NavigationManager.Uri).Query); await RunSearchAsync(); } private async void OnLocationChanged(object? sender, LocationChangedEventArgs e) { if (!_isAlive) return; if (!IsThisPage(e.Location)) return; // Parse query from the new URL and update state if it actually changed. string query = NavigationManager.ToAbsoluteUri(e.Location).Query; VoiceWorkFilterState next = VoiceWorkFilterState.FromQuery(query); if (next != FilterState) { FilterState = next; await RunSearchAsync(); await InvokeAsync(StateHasChanged); } } private bool IsThisPage(string absoluteUri) { string baseRelativePath = NavigationManager.ToBaseRelativePath(absoluteUri); return baseRelativePath.StartsWith("voiceworks", StringComparison.OrdinalIgnoreCase); } async Task OnFilterStateChanged(VoiceWorkFilterState next) { if (next == FilterState) return; UpdateUrl(next, false); } void UpdateUrl(VoiceWorkFilterState next, bool replace) { string basePath = new Uri(NavigationManager.Uri).GetLeftPart(UriPartial.Path); string uri = QueryHelpers.AddQueryString(basePath, next.ToQuery()); NavigationManager.NavigateTo(uri, replace: replace); } async Task RunSearchAsync() { await JS.InvokeVoidAsync("pageHelpers.scrollToTop"); try { _cts.Cancel(); _cts = new(); SearchVoiceWorksResponse? response = await Client.SearchAsync(FilterState.ToSearchRequest(), _cts.Token); searchResults = response?.Results; } catch (OperationCanceledException) { } } public async ValueTask DisposeAsync() { _isAlive = false; NavigationManager.LocationChanged -= OnLocationChanged; _cts.Cancel(); _cts.Dispose(); await Task.CompletedTask; } }