139 lines
4.0 KiB
Plaintext
139 lines
4.0 KiB
Plaintext
@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;
|
|
|
|
<PageTitle>Voice Works</PageTitle>
|
|
|
|
<h3>Voice Works</h3>
|
|
|
|
<VoiceWorkFilters Value="@FilterState" ValueChanged="OnFilterStateChanged" />
|
|
<JProductCollection Products="searchResults?.Items"></JProductCollection>
|
|
|
|
@if (searchResults is not null)
|
|
{
|
|
<JPagination PageNumber="@FilterState.PageNumber"
|
|
PageNumberChanged="@(pageNumber => OnFilterStateChanged(FilterState with { PageNumber = pageNumber }))"
|
|
PageSize="@FilterState.PageSize"
|
|
PageSizeChanged="@(pageSize => OnFilterStateChanged(FilterState with { PageSize = pageSize, PageNumber = 1 }))"
|
|
@bind-TotalItems="searchResults.TotalItems" />
|
|
}
|
|
|
|
@code {
|
|
private bool _suppressNextLocation;
|
|
private bool _isAlive = true;
|
|
//private bool IsLoading;
|
|
private CancellationTokenSource _cts = new();
|
|
|
|
VoiceWorkFilterState FilterState = new();
|
|
SearchResult<VoiceWorkSearchResult>? 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 (_suppressNextLocation)
|
|
{
|
|
_suppressNextLocation = false;
|
|
return;
|
|
}
|
|
|
|
if (!_isAlive)
|
|
return;
|
|
|
|
if (!IsThisPage(e.Location))
|
|
return;
|
|
|
|
string query = NavigationManager.ToAbsoluteUri(e.Location).Query;
|
|
VoiceWorkFilterState next = VoiceWorkFilterState.FromQuery(query);
|
|
|
|
if (next != FilterState)
|
|
{
|
|
FilterState = next;
|
|
await InvokeAsync(StateHasChanged);
|
|
RunSearchAsync();
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
FilterState = next;
|
|
|
|
// Optional immediate paint if you want instant visual feedback on filters:
|
|
//await InvokeAsync(StateHasChanged);
|
|
|
|
UpdateUrl(next, false);
|
|
RunSearchAsync();
|
|
}
|
|
|
|
void UpdateUrl(VoiceWorkFilterState next, bool replace)
|
|
{
|
|
string basePath = new Uri(NavigationManager.Uri).GetLeftPart(UriPartial.Path);
|
|
string uri = QueryHelpers.AddQueryString(basePath, next.ToQuery());
|
|
|
|
_suppressNextLocation = true;
|
|
|
|
NavigationManager.NavigateTo(uri, replace: replace);
|
|
}
|
|
|
|
async Task RunSearchAsync()
|
|
{
|
|
await JS.InvokeVoidAsync("pageHelpers.scrollToTop");
|
|
|
|
try
|
|
{
|
|
//IsLoading = true; // show skeletons NOW
|
|
//StateHasChanged(); // paint immediately
|
|
|
|
_cts.Cancel();
|
|
_cts = new();
|
|
|
|
SearchVoiceWorksResponse? response = await Client.SearchAsync(FilterState.ToSearchRequest(), _cts.Token);
|
|
searchResults = response?.Results;
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
|
|
}
|
|
finally
|
|
{
|
|
if (_isAlive)
|
|
{
|
|
//IsLoading = false; // hide skeletons
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
_isAlive = false;
|
|
NavigationManager.LocationChanged -= OnLocationChanged;
|
|
_cts.Cancel();
|
|
_cts.Dispose();
|
|
await Task.CompletedTask;
|
|
}
|
|
} |