109 lines
3.0 KiB
C#
109 lines
3.0 KiB
C#
using System.Text.Json;
|
|
|
|
namespace RolemasterDb.App.Frontend.AppState;
|
|
|
|
public sealed class RecentTablesState(BrowserStorageService browserStorage)
|
|
{
|
|
private const int MaxItems = 8;
|
|
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);
|
|
private bool isInitialized;
|
|
|
|
public IReadOnlyList<RecentTableEntry> Items { get; private set; } = [];
|
|
|
|
public event Action? Changed;
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
if (isInitialized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var storedValue = await browserStorage.GetItemAsync(BrowserStorageKeys.RecentTables);
|
|
Items = DeserializeItems(storedValue);
|
|
isInitialized = true;
|
|
Changed?.Invoke();
|
|
}
|
|
catch (JsonException)
|
|
{
|
|
Items = [];
|
|
isInitialized = true;
|
|
Changed?.Invoke();
|
|
}
|
|
catch (InvalidOperationException)
|
|
{
|
|
// JS interop is unavailable during prerender. Retry on the next interactive render.
|
|
}
|
|
}
|
|
|
|
public async Task RecordVisitAsync(string slug, string label, string family, int curationPercentage)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(slug) || string.IsNullOrWhiteSpace(label))
|
|
{
|
|
return;
|
|
}
|
|
|
|
await InitializeAsync();
|
|
|
|
var updatedItems = new List<RecentTableEntry>
|
|
{
|
|
new(
|
|
slug.Trim(),
|
|
label.Trim(),
|
|
family.Trim(),
|
|
curationPercentage,
|
|
DateTimeOffset.UtcNow)
|
|
};
|
|
|
|
foreach (var item in Items)
|
|
{
|
|
if (string.Equals(item.Slug, slug, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
updatedItems.Add(item);
|
|
if (updatedItems.Count == MaxItems)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
Items = updatedItems;
|
|
await PersistAsync();
|
|
Changed?.Invoke();
|
|
}
|
|
|
|
private async Task PersistAsync()
|
|
{
|
|
var serialized = JsonSerializer.Serialize(Items, SerializerOptions);
|
|
await browserStorage.SetItemAsync(BrowserStorageKeys.RecentTables, serialized);
|
|
}
|
|
|
|
private static IReadOnlyList<RecentTableEntry> DeserializeItems(string? storedValue)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(storedValue))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var items = JsonSerializer.Deserialize<List<RecentTableEntry>>(storedValue, SerializerOptions);
|
|
if (items is null || items.Count == 0)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
return items
|
|
.Where(item => !string.IsNullOrWhiteSpace(item.Slug) && !string.IsNullOrWhiteSpace(item.Label))
|
|
.GroupBy(item => item.Slug, StringComparer.OrdinalIgnoreCase)
|
|
.Select(group => group
|
|
.OrderByDescending(item => item.ViewedAtUtc)
|
|
.First())
|
|
.OrderByDescending(item => item.ViewedAtUtc)
|
|
.Take(MaxItems)
|
|
.ToList();
|
|
}
|
|
}
|