122 lines
3.0 KiB
C#
122 lines
3.0 KiB
C#
using JSMR.Application.Common.Search;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.AspNetCore.Components.Routing;
|
|
using Microsoft.JSInterop;
|
|
|
|
namespace JSMR.UI.Blazor.Shared;
|
|
|
|
public abstract class SearchPageBase<TState, TItem> : ComponentBase, IAsyncDisposable
|
|
where TState : notnull
|
|
{
|
|
[Inject]
|
|
protected NavigationManager Nav { get; set; } = default!;
|
|
|
|
[Inject]
|
|
protected IJSRuntime JS { get; set; } = default!;
|
|
|
|
protected TState State { get; private set; } = default!;
|
|
protected SearchResult<TItem>? Result { get; private set; }
|
|
protected bool IsLoading { get; private set; }
|
|
|
|
private bool _suppressNextLocation;
|
|
private bool _isAlive = true;
|
|
private CancellationTokenSource _cancellationTokenSource = new();
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
Nav.LocationChanged += OnLocationChanged;
|
|
State = ParseStateFromUri(Nav.Uri);
|
|
|
|
await RunSearchAsync();
|
|
}
|
|
|
|
protected async Task UpdateAsync(TState next)
|
|
{
|
|
if (Equals(next, State))
|
|
return;
|
|
|
|
State = next;
|
|
NavigateToState(next);
|
|
|
|
_ = RunSearchAsync();
|
|
}
|
|
|
|
private void NavigateToState(TState next)
|
|
{
|
|
string uri = BuildUri(next);
|
|
_suppressNextLocation = true;
|
|
Nav.NavigateTo(uri);
|
|
}
|
|
|
|
private async void OnLocationChanged(object? sender, LocationChangedEventArgs e)
|
|
{
|
|
if (_suppressNextLocation)
|
|
{
|
|
_suppressNextLocation = false;
|
|
return;
|
|
}
|
|
|
|
if (!_isAlive)
|
|
return;
|
|
|
|
if (!IsThisPage(e.Location))
|
|
return;
|
|
|
|
TState next = ParseStateFromUri(e.Location);
|
|
|
|
if (Equals(next, State))
|
|
return;
|
|
|
|
State = next;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
_ = RunSearchAsync();
|
|
}
|
|
|
|
private async Task RunSearchAsync()
|
|
{
|
|
await JS.InvokeVoidAsync("pageHelpers.scrollToTop");
|
|
|
|
try
|
|
{
|
|
IsLoading = true;
|
|
//StateHasChanged();
|
|
|
|
_cancellationTokenSource.Cancel();
|
|
_cancellationTokenSource = new();
|
|
|
|
Result = await ExecuteSearchAsync(State, _cancellationTokenSource.Token);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
|
|
}
|
|
finally
|
|
{
|
|
if (_isAlive)
|
|
{
|
|
IsLoading = false;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected abstract TState ParseStateFromUri(string absoluteUri);
|
|
protected abstract string BuildUri(TState state);
|
|
protected abstract bool IsThisPage(string absoluteUri);
|
|
protected abstract Task<SearchResult<TItem>> ExecuteSearchAsync(TState state, CancellationToken cancellationToken);
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
_isAlive = false;
|
|
|
|
Nav.LocationChanged -= OnLocationChanged;
|
|
|
|
_cancellationTokenSource.Cancel();
|
|
_cancellationTokenSource.Dispose();
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
} |