Skip to content

Commit dea4f93

Browse files
committed
Added Like option to blogpost
1 parent 662d3d5 commit dea4f93

File tree

7 files changed

+110
-1
lines changed

7 files changed

+110
-1
lines changed

LinkDotNet.Blog.TestUtilities/BlogPostBuilder.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class BlogPostBuilder
1010
private string url = "localhost";
1111
private bool isPublished = true;
1212
private string[] tags;
13+
private int likes;
1314

1415
public BlogPostBuilder WithTitle(string title)
1516
{
@@ -47,9 +48,17 @@ public BlogPostBuilder IsPublished(bool isPublished = true)
4748
return this;
4849
}
4950

51+
public BlogPostBuilder WithLikes(int likes)
52+
{
53+
this.likes = likes;
54+
return this;
55+
}
56+
5057
public BlogPost Build()
5158
{
52-
return BlogPost.Create(title, shortDescription, content, url, isPublished, tags);
59+
var blogPost = BlogPost.Create(title, shortDescription, content, url, isPublished, tags);
60+
blogPost.Likes = likes;
61+
return blogPost;
5362
}
5463
}
5564
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Blazored.LocalStorage;
2+
using Bunit;
3+
using FluentAssertions;
4+
using LinkDotNet.Blog.TestUtilities;
5+
using LinkDotNet.Blog.Web.Shared;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Moq;
8+
using Xunit;
9+
10+
namespace LinkDotNet.Blog.UnitTests.Web.Shared
11+
{
12+
public class LikeTests : TestContext
13+
{
14+
[Theory]
15+
[InlineData(0, "0 Likes")]
16+
[InlineData(1, "1 Like")]
17+
[InlineData(2, "2 Likes")]
18+
public void ShouldDisplayLikes(int likes, string expectedText)
19+
{
20+
Services.AddScoped(_ => new Mock<ILocalStorageService>().Object);
21+
var blogPost = new BlogPostBuilder().WithLikes(likes).Build();
22+
var cut = RenderComponent<Like>(
23+
p => p.Add(l => l.BlogPost, blogPost));
24+
25+
var label = cut.Find("small").TextContent;
26+
27+
label.Should().Be(expectedText);
28+
}
29+
}
30+
}

LinkDotNet.Blog.Web/LinkDotNet.Blog.Web.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9+
<PackageReference Include="Blazored.LocalStorage" Version="4.1.2" />
910
<PackageReference Include="Blazored.Toast" Version="3.1.2" />
1011
<PackageReference Include="Markdig" Version="0.25.0" />
1112
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.7" />

LinkDotNet.Blog.Web/Pages/BlogPostPage.razor

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ else
3232
@(RenderMarkupString(BlogPost.Content))
3333
</div>
3434
</div>
35+
<Like BlogPost="@BlogPost" OnBlogPostLiked="@UpdateLikes"></Like>
3536
</div>
3637
</div>
3738
}
@@ -55,4 +56,11 @@ else
5556
StateHasChanged();
5657
}
5758
}
59+
60+
private async Task UpdateLikes(bool hasLiked)
61+
{
62+
BlogPost = await _repository.GetByIdAsync(BlogPostId);
63+
BlogPost.Likes = hasLiked ? BlogPost.Likes + 1 : BlogPost.Likes - 1;
64+
await _repository.StoreAsync(BlogPost);
65+
}
5866
}

LinkDotNet.Blog.Web/Shared/Like.razor

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
@using LinkDotNet.Domain
2+
@using Blazored.LocalStorage
3+
@using LinkDotNet.Infrastructure.Persistence
4+
@inject ILocalStorageService _localStorage
5+
<div style="float: right">
6+
<small>@BlogPost.Likes @LikeText</small>
7+
<button class="btn @BtnClass" @onclick="LikeBlogPost"><i class="far fa-thumbs-up"></i> @LikeTextButton</button>
8+
</div>
9+
10+
@code {
11+
[Parameter]
12+
public BlogPost BlogPost { get; set; }
13+
14+
[Parameter]
15+
public EventCallback<bool> OnBlogPostLiked { get; set; }
16+
17+
private bool HasLiked { get; set; }
18+
19+
private string BtnClass => HasLiked ? "btn-secondary" : "btn-primary";
20+
21+
private string LikeTextButton => HasLiked ? "Unlike" : "Like";
22+
23+
private string LikeText => BlogPost.Likes == 1 ? "Like" : "Likes";
24+
25+
protected override async Task OnAfterRenderAsync(bool firstRender)
26+
{
27+
if (firstRender)
28+
{
29+
HasLiked = await GetHasLiked();
30+
StateHasChanged();
31+
}
32+
}
33+
34+
private async Task LikeBlogPost()
35+
{
36+
// Prevent multiple open sites to like / unlike multiple times
37+
var hasLikedFromLocalStorage = await GetHasLiked();
38+
if (HasLiked != hasLikedFromLocalStorage)
39+
{
40+
return;
41+
}
42+
43+
HasLiked = !HasLiked;
44+
await OnBlogPostLiked.InvokeAsync(HasLiked);
45+
await _localStorage.SetItemAsync("hasLiked", HasLiked);
46+
}
47+
48+
private async Task<bool> GetHasLiked()
49+
{
50+
if (await _localStorage.ContainKeyAsync("hasLiked"))
51+
{
52+
return await _localStorage.GetItemAsync<bool>("hasLiked");
53+
}
54+
55+
return false;
56+
}
57+
}

LinkDotNet.Blog.Web/Startup.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Blazored.LocalStorage;
12
using Blazored.Toast;
23
using LinkDotNet.Blog.Web.Authentication.Auth0;
34
using LinkDotNet.Blog.Web.RegistrationExtensions;
@@ -39,6 +40,7 @@ public void ConfigureServices(IServiceCollection services)
3940
services.UseAuth0Authentication(Configuration);
4041

4142
services.AddBlazoredToast();
43+
services.AddBlazoredLocalStorage();
4244
}
4345

4446
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

LinkDotNet.Domain/BlogPost.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ private BlogPost()
2626

2727
public bool IsPublished { get; set; }
2828

29+
public int Likes { get; set; }
30+
2931
public static BlogPost Create(
3032
string title,
3133
string shortDescription,

0 commit comments

Comments
 (0)