Implemented local setting persistence and fixed main page search bug.

This commit is contained in:
Harrison Deng 2021-06-04 19:12:55 -05:00
parent 04f6657ed3
commit 11fa15fe62
4 changed files with 72 additions and 40 deletions

View File

@ -1,11 +1,13 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using MultiShop.Client.Module;
using MultiShop.Client.Shared;
using MultiShop.Shared.Models;
using MultiShop.Shop.Framework;
@ -13,19 +15,26 @@ namespace MultiShop.Client
{
public partial class App
{
[Inject]
private IJSRuntime JS { get; set; }
[Inject]
private IHttpClientFactory HttpClientFactory {get; set;}
private IJSObjectReference localStorageManager;
private ICollection<RuntimeDependencyManager.Dependency> dependencies = new List<RuntimeDependencyManager.Dependency>();
protected override void OnInitialized()
{
base.OnInitialized();
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(IReadOnlyDictionary<string, IShop>), "Shops", DownloadShops));
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(IJSObjectReference), "JS Modules", (pHttp, http, auth, logger) => new ValueTask<object>(localStorageManager), "LocalStorageManager"));
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(IJSObjectReference), "JS Modules", async (pHttp, http, auth, logger) => await JS.InvokeAsync<IJSObjectReference>("import", "./js/Components/ComponentSupport.js"), "ComponentSupport"));
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(IReadOnlyDictionary<string, IShop>), "Shops", async (publicHttp, authenticatedHttp, auth, logger) => await (new ShopModuleLoader(publicHttp, logger)).GetShops()));
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(ApplicationProfile), "Application Profile", DownloadApplicationProfile));
}
private async ValueTask<object> DownloadShops(HttpClient publicHttp, HttpClient http, AuthenticationState authState, ILogger logger)
protected override async Task OnInitializedAsync()
{
ShopModuleLoader loader = new ShopModuleLoader(publicHttp, logger);
return await loader.GetShops();
await base.OnInitializedAsync();
localStorageManager = await JS.InvokeAsync<IJSObjectReference>("import", "./js/LocalStorageManager.js");
}
private async ValueTask<object> DownloadApplicationProfile(HttpClient publicHttp, HttpClient http, AuthenticationState authState, ILogger logger)
@ -39,7 +48,10 @@ namespace MultiShop.Client
return await response.Content.ReadFromJsonAsync<ApplicationProfile>();
}
}
ApplicationProfile profile = await localStorageManager.InvokeAsync<ApplicationProfile>("retrieve", "ApplicationProfile");
if (profile != null) return profile;
return new ApplicationProfile();
}
}
}

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using MultiShop.Client.Services;
using MultiShop.Shared.Models;
@ -70,6 +71,7 @@ namespace MultiShop.Client.Pages
Logger.LogDebug($"User is authenticated. Attempting to save configuration to server.");
await Http.PutAsJsonAsync("Profile/Application", ApplicationProfile);
}
await RuntimeDependencyManager.Get<IJSObjectReference>("LocalStorageManager").InvokeVoidAsync("save", "ApplicationProfile", ApplicationProfile);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
using MultiShop.Client.Extensions;
using MultiShop.Client.Listing;
using MultiShop.Client.Services;
@ -17,9 +18,6 @@ namespace MultiShop.Client.Pages
{
public partial class Search : IAsyncDisposable
{
[Inject]
private LayoutStateChangeNotifier LayoutStateChangeNotifier { get; set; }
[Inject]
private ILogger<Search> Logger { get; set; }
@ -53,7 +51,6 @@ namespace MultiShop.Client.Pages
protected override void OnInitialized()
{
base.OnInitialized();
LayoutStateChangeNotifier.Notify += UpdateState;
Shops = RuntimeDependencyManager.Get<IReadOnlyDictionary<string, IShop>>();
}
@ -71,36 +68,24 @@ namespace MultiShop.Client.Pages
{
activeSearchProfile = await searchProfileResponse.Content.ReadFromJsonAsync<SearchProfile>();
}
else
{
Logger.LogWarning("Could not load search profile from server. Using default.");
activeSearchProfile = new SearchProfile();
}
HttpResponseMessage resultsProfileResponse = await Http.GetAsync("Profile/Results");
if (resultsProfileResponse.IsSuccessStatusCode)
{
activeResultsProfile = await resultsProfileResponse.Content.ReadFromJsonAsync<ResultsProfile>();
}
else
{
Logger.LogWarning("Could not load results profile from server. Using default.");
activeResultsProfile = new ResultsProfile();
}
}
else
{
activeSearchProfile = new SearchProfile();
activeResultsProfile = new ResultsProfile();
}
activeSearchProfile.ShopStates.TotalShops = Shops.Count;
}
IJSObjectReference localStorageManager = RuntimeDependencyManager.Get<IJSObjectReference>("LocalStorageManager");
if (activeSearchProfile == null) activeSearchProfile = await localStorageManager.InvokeAsync<SearchProfile>("retrieve", "SearchProfile");
if (activeResultsProfile == null) activeResultsProfile = await localStorageManager.InvokeAsync<ResultsProfile>("retrieve", "ResultsProfile");
protected override async Task OnParametersSetAsync()
{
await base.OnParametersSetAsync();
if (!string.IsNullOrEmpty(Query))
if (activeSearchProfile == null) activeSearchProfile = new SearchProfile();
if (activeResultsProfile == null) activeResultsProfile = new ResultsProfile();
activeSearchProfile.ShopStates.TotalShops = Shops.Count;
if (Query != null)
{
searchBar.Searching = true;
await PerformSearch(Query);
}
}
@ -111,9 +96,6 @@ namespace MultiShop.Client.Pages
if (firstRender)
{
searchBar.Query = Query;
searchBar.Searching = true;
await PerformSearch(Query);
searchBar.Searching = false;
}
}
@ -121,6 +103,7 @@ namespace MultiShop.Client.Pages
{
if (string.IsNullOrWhiteSpace(query)) return;
if (status.Searching) return;
searchBar.Searching = true;
SearchProfile searchProfile = activeSearchProfile.DeepCopy();
status.Searching = true;
Logger.LogDebug($"Received search request for \"{query}\".");
@ -187,6 +170,7 @@ namespace MultiShop.Client.Pages
}
status.Searching = false;
status.Searched = true;
searchBar.Searching = false;
int tagsAdded = 0;
foreach (ResultsProfile.Category c in greatest.Keys)
@ -272,12 +256,6 @@ namespace MultiShop.Client.Pages
StateHasChanged();
}
private async Task UpdateState() {
await InvokeAsync(() => {
StateHasChanged();
});
}
public async ValueTask DisposeAsync()
{
AuthenticationState authState = await AuthenticationStateTask;
@ -286,7 +264,9 @@ namespace MultiShop.Client.Pages
await Http.PutAsJsonAsync("Profile/Search", activeSearchProfile);
await Http.PutAsJsonAsync("Profile/Results", activeResultsProfile);
}
LayoutStateChangeNotifier.Notify -= UpdateState;
IJSObjectReference localStorageManager = RuntimeDependencyManager.Get<IJSObjectReference>("LocalStorageManager");
await localStorageManager.InvokeVoidAsync("save", "SearchProfile", activeSearchProfile);
await localStorageManager.InvokeVoidAsync("save", "ResultsProfile", activeResultsProfile);
}
public class Status

View File

@ -0,0 +1,38 @@
const APP_STORAGE_KEY = "MultiShop"
export function save(key, value) {
try {
localStorage.setItem(APP_STORAGE_KEY + "/" + key, JSON.stringify(value));
} catch (error) {
console.warn("Failed to save value with key: " + key);
return false;
}
return true;
}
export function retrieve(key) {
let value = localStorage.getItem(APP_STORAGE_KEY + "/" + key);
if (value == null) return null;
try {
return JSON.parse(value);
} catch (error) {
if (error instanceof SyntaxError) {
console.warn("Unable to parse value for key \"" + key + "\". Removing.");
remove(key);
return null;
}
}
}
export function remove(key) {
localStorage.removeItem(APP_STORAGE_KEY + "/" + key);
}
export function clear() {
for (let i = 0; i < localStorage.length; i++) {
let name = localStorage.key(i);
if (name.startsWith(APP_STORAGE_KEY + "/")) {
localStorage.removeItem(name);
}
}
}