Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@
</ItemGroup>
<ItemGroup Label="Tools">
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="Microsoft.Playwright" Version="1.50.0" />
<PackageVersion Include="Microsoft.Playwright" Version="1.51.0" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task SetBookmark(string postId, bool isBookmarked)

private async Task InitializeIfNotExists()
{
if (!(await localStorageService.ContainKeyAsync("bookmarks")))
if (!(await localStorageService.ContainsKeyAsync("bookmarks")))
{
await localStorageService.SetItemAsync("bookmarks", new List<string>());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
{
await using var _ = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Features/Home/Components/ThemeToggler.razor.js");

currentTheme = await LocalStorageService.ContainKeyAsync(StorageKey)
currentTheme = await LocalStorageService.ContainsKeyAsync(StorageKey)
? await LocalStorageService.GetItemAsync<string>(StorageKey)
: await JSRuntime.InvokeAsync<string>("getCurrentSystemPreference");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace LinkDotNet.Blog.Web.Features.Services;

public interface ILocalStorageService
{
ValueTask<bool> ContainKeyAsync(string key);
ValueTask<bool> ContainsKeyAsync(string key);

ValueTask<T> GetItemAsync<T>(string key);

Expand Down
49 changes: 44 additions & 5 deletions src/LinkDotNet.Blog.Web/Features/Services/LocalStorageService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;

Expand All @@ -13,10 +15,47 @@ public LocalStorageService(ProtectedLocalStorage localStorage)
this.localStorage = localStorage;
}

public async ValueTask<bool> ContainKeyAsync(string key) => (await localStorage.GetAsync<object>(key)).Success;
public async ValueTask<bool> ContainsKeyAsync(string key)
{
try
{
return (await localStorage.GetAsync<object>(key)).Success;
}
catch (CryptographicException)
{
await localStorage.DeleteAsync(key);
return false;
}
}

public async ValueTask<T> GetItemAsync<T>(string key) => (await localStorage.GetAsync<T>(key)).Value
?? throw new KeyNotFoundException($"Key {key} not found");
public async ValueTask<T> GetItemAsync<T>(string key)
{
try
{
var result = await localStorage.GetAsync<T>(key);
if (!result.Success)
{
throw new KeyNotFoundException($"Key {key} not found");
}
return result.Value!;
}
catch (CryptographicException)
{
await localStorage.DeleteAsync(key);
throw new KeyNotFoundException($"Key {key} was invalid and has been removed");
}
}

public async ValueTask SetItemAsync<T>(string key, T value) => await localStorage.SetAsync(key, value!);
public async ValueTask SetItemAsync<T>(string key, T value)
{
try
{
await localStorage.SetAsync(key, value!);
}
catch (CryptographicException)
{
await localStorage.DeleteAsync(key);
throw new InvalidOperationException($"Could not set value for key {key}. The key has been removed.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@inject ILocalStorageService LocalStorage

<button class="btn @ButtonClass d-inline-flex align-items-center gap-2" @onclick="LikeBlogPost">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor"
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor"
class="bi bi-hand-thumbs-up@(HasLiked ? "-fill" : "")" viewBox="0 0 16 16">
@if (HasLiked)
{
Expand All @@ -29,8 +29,8 @@

private bool HasLiked { get; set; }

private string ButtonClass => HasLiked
? "btn-primary"
private string ButtonClass => HasLiked
? "btn-primary"
: "btn-outline-secondary";

protected override void OnParametersSet()
Expand Down Expand Up @@ -68,7 +68,7 @@

private async Task<bool> GetHasLiked()
{
if (await LocalStorage.ContainKeyAsync($"hasLiked/{BlogPost.Id}"))
if (await LocalStorage.ContainsKeyAsync($"hasLiked/{BlogPost.Id}"))
{
return await LocalStorage.GetItemAsync<bool>($"hasLiked/{BlogPost.Id}");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public async Task ShouldSubtractLikeOnEvent()
using var ctx = new BunitContext();
var localStorage = Substitute.For<ILocalStorageService>();
var hasLikedStorage = $"hasLiked/{publishedPost.Id}";
localStorage.ContainKeyAsync(hasLikedStorage).Returns(true);
localStorage.ContainsKeyAsync(hasLikedStorage).Returns(true);
localStorage.GetItemAsync<bool>(hasLikedStorage).Returns(true);
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
RegisterComponents(ctx, localStorage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void ShouldSetSystemDefault()
public void ShouldSetFromLocalStorage()
{
var localStorage = Substitute.For<ILocalStorageService>();
localStorage.ContainKeyAsync("preferred-theme").Returns(true);
localStorage.ContainsKeyAsync("preferred-theme").Returns(true);
localStorage.GetItemAsync<string>("preferred-theme").Returns("dark");
Services.AddScoped(_ => localStorage);
JSInterop.SetupModule("./Features/Home/Components/ThemeToggler.razor.js");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task ShouldSetLocalStorageVariableOnClick()
public void ShouldCheckLocalStorageOnInit()
{
var localStorage = Substitute.For<ILocalStorageService>();
localStorage.ContainKeyAsync("hasLiked/id").Returns(true);
localStorage.ContainsKeyAsync("hasLiked/id").Returns(true);
localStorage.GetItemAsync<bool>("hasLiked/id").Returns(true);
Services.AddScoped(_ => localStorage);
var blogPost = new BlogPostBuilder().Build();
Expand All @@ -87,7 +87,7 @@ public void ShouldCheckStorageOnClickAgainAndDoNothingOnMismatch()
var cut = Render<Like>(
p => p.Add(l => l.BlogPost, blogPost)
.Add(l => l.OnBlogPostLiked, _ => wasClicked = true));
localStorage.ContainKeyAsync("hasLiked/id").Returns(true);
localStorage.ContainsKeyAsync("hasLiked/id").Returns(true);
localStorage.GetItemAsync<bool>("hasLiked/id").Returns(true);

cut.Find("span").Click();
Expand Down