Implemented local setting persistence and fixed main page search bug.
This commit is contained in:
parent
04f6657ed3
commit
11fa15fe62
@ -1,11 +1,13 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
using MultiShop.Client.Module;
|
using MultiShop.Client.Module;
|
||||||
using MultiShop.Client.Shared;
|
|
||||||
using MultiShop.Shared.Models;
|
using MultiShop.Shared.Models;
|
||||||
using MultiShop.Shop.Framework;
|
using MultiShop.Shop.Framework;
|
||||||
|
|
||||||
@ -13,19 +15,26 @@ namespace MultiShop.Client
|
|||||||
{
|
{
|
||||||
public partial class App
|
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>();
|
private ICollection<RuntimeDependencyManager.Dependency> dependencies = new List<RuntimeDependencyManager.Dependency>();
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
base.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));
|
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);
|
await base.OnInitializedAsync();
|
||||||
return await loader.GetShops();
|
localStorageManager = await JS.InvokeAsync<IJSObjectReference>("import", "./js/LocalStorageManager.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask<object> DownloadApplicationProfile(HttpClient publicHttp, HttpClient http, AuthenticationState authState, ILogger logger)
|
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>();
|
return await response.Content.ReadFromJsonAsync<ApplicationProfile>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ApplicationProfile profile = await localStorageManager.InvokeAsync<ApplicationProfile>("retrieve", "ApplicationProfile");
|
||||||
|
if (profile != null) return profile;
|
||||||
return new ApplicationProfile();
|
return new ApplicationProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
using MultiShop.Client.Services;
|
using MultiShop.Client.Services;
|
||||||
using MultiShop.Shared.Models;
|
using MultiShop.Shared.Models;
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ namespace MultiShop.Client.Pages
|
|||||||
Logger.LogDebug($"User is authenticated. Attempting to save configuration to server.");
|
Logger.LogDebug($"User is authenticated. Attempting to save configuration to server.");
|
||||||
await Http.PutAsJsonAsync("Profile/Application", ApplicationProfile);
|
await Http.PutAsJsonAsync("Profile/Application", ApplicationProfile);
|
||||||
}
|
}
|
||||||
|
await RuntimeDependencyManager.Get<IJSObjectReference>("LocalStorageManager").InvokeVoidAsync("save", "ApplicationProfile", ApplicationProfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
using MultiShop.Client.Extensions;
|
using MultiShop.Client.Extensions;
|
||||||
using MultiShop.Client.Listing;
|
using MultiShop.Client.Listing;
|
||||||
using MultiShop.Client.Services;
|
using MultiShop.Client.Services;
|
||||||
@ -17,9 +18,6 @@ namespace MultiShop.Client.Pages
|
|||||||
{
|
{
|
||||||
public partial class Search : IAsyncDisposable
|
public partial class Search : IAsyncDisposable
|
||||||
{
|
{
|
||||||
[Inject]
|
|
||||||
private LayoutStateChangeNotifier LayoutStateChangeNotifier { get; set; }
|
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private ILogger<Search> Logger { get; set; }
|
private ILogger<Search> Logger { get; set; }
|
||||||
|
|
||||||
@ -53,7 +51,6 @@ namespace MultiShop.Client.Pages
|
|||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
LayoutStateChangeNotifier.Notify += UpdateState;
|
|
||||||
Shops = RuntimeDependencyManager.Get<IReadOnlyDictionary<string, IShop>>();
|
Shops = RuntimeDependencyManager.Get<IReadOnlyDictionary<string, IShop>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,36 +68,24 @@ namespace MultiShop.Client.Pages
|
|||||||
{
|
{
|
||||||
activeSearchProfile = await searchProfileResponse.Content.ReadFromJsonAsync<SearchProfile>();
|
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");
|
HttpResponseMessage resultsProfileResponse = await Http.GetAsync("Profile/Results");
|
||||||
if (resultsProfileResponse.IsSuccessStatusCode)
|
if (resultsProfileResponse.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
activeResultsProfile = await resultsProfileResponse.Content.ReadFromJsonAsync<ResultsProfile>();
|
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()
|
if (activeSearchProfile == null) activeSearchProfile = new SearchProfile();
|
||||||
{
|
if (activeResultsProfile == null) activeResultsProfile = new ResultsProfile();
|
||||||
await base.OnParametersSetAsync();
|
activeSearchProfile.ShopStates.TotalShops = Shops.Count;
|
||||||
if (!string.IsNullOrEmpty(Query))
|
|
||||||
|
if (Query != null)
|
||||||
{
|
{
|
||||||
|
searchBar.Searching = true;
|
||||||
await PerformSearch(Query);
|
await PerformSearch(Query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,9 +96,6 @@ namespace MultiShop.Client.Pages
|
|||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
searchBar.Query = Query;
|
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 (string.IsNullOrWhiteSpace(query)) return;
|
||||||
if (status.Searching) return;
|
if (status.Searching) return;
|
||||||
|
searchBar.Searching = true;
|
||||||
SearchProfile searchProfile = activeSearchProfile.DeepCopy();
|
SearchProfile searchProfile = activeSearchProfile.DeepCopy();
|
||||||
status.Searching = true;
|
status.Searching = true;
|
||||||
Logger.LogDebug($"Received search request for \"{query}\".");
|
Logger.LogDebug($"Received search request for \"{query}\".");
|
||||||
@ -187,6 +170,7 @@ namespace MultiShop.Client.Pages
|
|||||||
}
|
}
|
||||||
status.Searching = false;
|
status.Searching = false;
|
||||||
status.Searched = true;
|
status.Searched = true;
|
||||||
|
searchBar.Searching = false;
|
||||||
|
|
||||||
int tagsAdded = 0;
|
int tagsAdded = 0;
|
||||||
foreach (ResultsProfile.Category c in greatest.Keys)
|
foreach (ResultsProfile.Category c in greatest.Keys)
|
||||||
@ -272,12 +256,6 @@ namespace MultiShop.Client.Pages
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateState() {
|
|
||||||
await InvokeAsync(() => {
|
|
||||||
StateHasChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
AuthenticationState authState = await AuthenticationStateTask;
|
AuthenticationState authState = await AuthenticationStateTask;
|
||||||
@ -286,7 +264,9 @@ namespace MultiShop.Client.Pages
|
|||||||
await Http.PutAsJsonAsync("Profile/Search", activeSearchProfile);
|
await Http.PutAsJsonAsync("Profile/Search", activeSearchProfile);
|
||||||
await Http.PutAsJsonAsync("Profile/Results", activeResultsProfile);
|
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
|
public class Status
|
||||||
|
38
src/MultiShop/Client/wwwroot/js/LocalStorageManager.js
Normal file
38
src/MultiShop/Client/wwwroot/js/LocalStorageManager.js
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user