Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

87 show personalized favorites #131

Merged
merged 62 commits into from
May 14, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
351f12a
Add UserContract table to database
JacobBredin May 7, 2022
71ad5b3
Add services and infrastructure
JacobBredin May 7, 2022
341f881
Add server side endpoints
JacobBredin May 7, 2022
2df1222
Add client endpoints
JacobBredin May 7, 2022
eb4c535
Fix broken tests
JacobBredin May 7, 2022
f0fd186
Remove IsFavorite from contract
JacobBredin May 7, 2022
44485ba
Fix documentation
pkasinski May 7, 2022
ec3928d
Remove unnecessary method from FavoritesController
pkasinski May 7, 2022
c2c24b0
Rename methods in FavoritesController
pkasinski May 7, 2022
c807fc1
Move unit tests to separate files
JacobBredin May 7, 2022
2c5f846
Merge branch '87-show-personalized-favorites-2' of https://github.com…
JacobBredin May 7, 2022
4e745bf
Incomplete tests for FavoritesController
JacobBredin May 7, 2022
dac7dfa
Add tests to FavoriteContractServiceTests
pkasinski May 7, 2022
fbc8178
Add FavoriteButton unit tests
JacobBredin May 8, 2022
87c7d3b
Merge branch '87-show-personalized-favorites-2' of https://github.com…
JacobBredin May 8, 2022
9e69123
Fix incorrect logger in EFFavoriteRepository
JacobBredin May 8, 2022
8b60139
Change a test in FavoriteContractServiceTests
pkasinski May 8, 2022
10bf183
Rename method in FavoritesController
pkasinski May 8, 2022
5dc8b76
Add tests to FavoritesControllerTests
pkasinski May 8, 2022
b185b5b
Add exception handling
JacobBredin May 8, 2022
c7aa5a7
Add unit tests
JacobBredin May 8, 2022
ca74421
Merge branch '87-show-personalized-favorites-2' of https://github.com…
JacobBredin May 8, 2022
bb75820
Add and fix unit tests
JacobBredin May 9, 2022
d4573e4
Add exception handling to FavoritesController
JacobBredin May 9, 2022
672125d
Add migration for removing IsFavorite in contract
JacobBredin May 9, 2022
7607af5
Merge master into branch
JacobBredin May 9, 2022
cb5b599
Refactor FavoritesService to be smarter
JacobBredin May 9, 2022
6c52986
Rename method
JacobBredin May 9, 2022
2e0ca4a
Fix tests
JacobBredin May 9, 2022
a4127d0
Fix tests
JacobBredin May 9, 2022
fa58bcc
merge master into branch
JacobBredin May 9, 2022
df710e1
Apply suggestions from code review
JacobBredin May 9, 2022
7c83eeb
Fix broken test
JacobBredin May 9, 2022
7db80af
Rename FetchAllFavorites to FetchAll
pkasinski May 9, 2022
07d84d8
Hide user collection in contract
JacobBredin May 9, 2022
79c42ec
Merge branch '87-show-personalized-favorites-2' of https://github.com…
JacobBredin May 9, 2022
74d2501
Add documentation to EF navigation property
JacobBredin May 10, 2022
0e9c90e
Rename database table
JacobBredin May 11, 2022
560944d
Move favorite methods to user service and repo
JacobBredin May 11, 2022
9ba4b44
Change the structure of endpoint URLs in FavoritesController
pkasinski May 11, 2022
3a534d4
Remove Favorite service and repo
JacobBredin May 11, 2022
ebf003f
Fix broken test for contract repo
JacobBredin May 11, 2022
6628e1b
Make adjustments in FavoritesController
pkasinski May 11, 2022
14b9cfd
Add tests to FavoritesControllerTests
pkasinski May 11, 2022
57af96f
Fix broken favorites tests
JacobBredin May 11, 2022
e1c7208
Move SetFavoriteContract.cs to Application/Users
pkasinski May 11, 2022
c9d7608
Fix broken tests
JacobBredin May 11, 2022
674e641
Fix merge conflicts
JacobBredin May 11, 2022
74e281f
Fix build error
JacobBredin May 11, 2022
e890421
Rename method in ContractCard
pkasinski May 11, 2022
c50a836
Remove null-forgiving operator
pkasinski May 11, 2022
f295b5c
Rename SetFavoriteContract to FavoriteContractDto
JacobBredin May 12, 2022
87fad1c
Fix favorite controller endpoint bug
JacobBredin May 12, 2022
ac9d14a
Add check to LoggedInUser
JacobBredin May 12, 2022
9ec7c15
Make adjustments in FavoriteButtonTests
pkasinski May 12, 2022
5aba061
Apply suggestions from code review
JacobBredin May 12, 2022
038569b
Merge branch 'master' into 87-show-personalized-favorites-2
JacobBredin May 12, 2022
2f706ff
Rewrite documentation in unit test
JacobBredin May 12, 2022
b62ca10
Inject ISessionService
pkasinski May 13, 2022
58d2c1e
Fix tests in FavoriteButtonTests and FavoriteCardsTests
pkasinski May 13, 2022
3c1ec80
Use the IsAuthenticated property
pkasinski May 13, 2022
137d604
Merge master into branch
JacobBredin May 14, 2022
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
6 changes: 0 additions & 6 deletions src/Application/Contracts/ContractService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,6 @@ public IEnumerable<ContractPreviewDto> SearchUnauthorized(string query)
return ConvertToPreviews(results);
}

/// <inheritdoc />
public IEnumerable<Contract> FetchFavorites()
{
return _repo.Favorites;
}

/// <inheritdoc />
public void UpdateContract(Contract contract)
{
Expand Down
6 changes: 0 additions & 6 deletions src/Application/Contracts/IContractRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ public interface IContractRepository
/// </summary>
IEnumerable<Contract> Recent { get; }

/// <summary>
/// Gets all contracts marked as favorites.
/// </summary>
/// <returns>The contract with a favorite mark.</returns>
IEnumerable<Contract> Favorites { get; }

/// <summary>
/// Adds a new contract to store.
/// </summary>
Expand Down
6 changes: 0 additions & 6 deletions src/Application/Contracts/IContractService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@ public interface IContractService
/// <returns>Whether the removal was successful.</returns>
bool Remove(Guid id);

/// <summary>
/// Gets contracts marked as favorites.
/// </summary>
/// <returns>All favorite marked contracts.</returns>
IEnumerable<Contract> FetchFavorites();

/// <summary>
/// Updates the contract in the repository.
/// </summary>
Expand Down
42 changes: 42 additions & 0 deletions src/Application/Favorites/FavoriteContractService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Domain.Contracts;

namespace Application.FavoriteContracts;

/// <inheritdoc />
public class FavoriteContractService : IFavoriteContractService
{
private readonly IFavoriteContractRepository _repo;

/// <summary>
/// Constructs favorite service.
/// </summary>
/// <param name="repo">Where to store and fetch favorites from.</param>
public FavoriteContractService(IFavoriteContractRepository repo)
{
_repo = repo;
}

/// <inheritdoc />
public void Add(string userName, Guid contractId)
{
_repo.Add(userName, contractId);
}

/// <inheritdoc />
public bool CheckIfFavorite(string userName, Guid contractId)
{
return _repo.CheckIfFavorite(userName, contractId);
}

/// <inheritdoc/>
public IEnumerable<Contract> FetchAllFavorites(string userName)
{
return _repo.FetchAllFavorites(userName);
}

/// <inheritdoc/>
public bool Remove(string userName, Guid contractId)
{
return _repo.Remove(userName, contractId);
}
}
39 changes: 39 additions & 0 deletions src/Application/Favorites/IFavoriteContractRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Domain.Contracts;

namespace Application.FavoriteContracts;

/// <summary>
/// Logic for fetching and storing favorites.
/// </summary>
public interface IFavoriteContractRepository
{
/// <summary>
/// Checks if the contract is marked as favorite by the user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <param name="contractId">The id of the contract.</param>
/// <returns>Whether the contract was marked as favorite.</returns>
bool CheckIfFavorite(string userName, Guid contractId);
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Fetches all contracts marked as favorite by a certain user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <returns>All contracts marked as favorite by the user.</returns>
IEnumerable<Contract> FetchAllFavorites(string userName);
pkasinski marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Adds a favorite contract to store, for a certain user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <param name="contractId">The id of the contract.</param>
void Add(string userName, Guid contractId);

/// <summary>
/// Removes a stored favorite contract, for a certain user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <param name="contractId">The id of the contract.</param>
/// <returns>If the removal was successful.</returns>
bool Remove(string userName, Guid contractId);
}
39 changes: 39 additions & 0 deletions src/Application/Favorites/IFavoriteContractService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Domain.Contracts;

namespace Application.FavoriteContracts;

/// <summary>
/// Used for interacting with favorite logic.
/// </summary>
public interface IFavoriteContractService
{
/// <summary>
/// Gets all contracts marked as favorite by a certain user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <returns>All contracts marked as favorite by the user.</returns>
IEnumerable<Contract> FetchAllFavorites(string userName);
pkasinski marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Checks if the contract is marked as favorite by the user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <param name="contractId">The id of the contract.</param>
/// <returns>Whether the contract was marked as favorite.</returns>
bool CheckIfFavorite(string userName, Guid contractId);
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Adds a favorite contract for a certain user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <param name="contractId">The id of the contract.</param>
void Add(string userName, Guid contractId);

/// <summary>
/// Removes a favorite contract for a certain user.
/// </summary>
/// <param name="userName">The name of the user.</param>
/// <param name="contractId">The id of the contract.</param>
/// <returns>Whether the removal was successful.</returns>
bool Remove(string userName, Guid contractId);
}
2 changes: 2 additions & 0 deletions src/Application/InjectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Application.Contracts;
using Application.FavoriteContracts;
using Application.Search;
using Application.StatusUpdates;
using Application.Users;
Expand All @@ -19,6 +20,7 @@ public static class InjectionExtensions
public static IServiceCollection AddApplication(this IServiceCollection services)
{
return services.AddTransient<IContractService, ContractService>()
.AddTransient<IFavoriteContractService, FavoriteContractService>()
.AddTransient<IStatusUpdateService, NotificationService>()
.AddTransient<IUserService, UserService>()
.AddScoped(typeof(SearchEngine<>))
Expand Down
22 changes: 22 additions & 0 deletions src/Application/MessagePassing/SetFavoriteContract.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Application.MessagePassing;
pkasinski marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Used to send information about making a Contract a users favorite.
/// </summary>
public class SetFavoriteContract
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// Gets the id of the user.
/// </summary>
public string UserName { get; init; } = string.Empty;

/// <summary>
/// Gets the id of the contract.
/// </summary>
public Guid ContractId { get; init; }

/// <summary>
/// Gets a value indicating whether gets if the Contract should be a favorite or not.
/// </summary>
public bool IsFavorite { get; init; }
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved
}
9 changes: 4 additions & 5 deletions src/Client/Pages/Contracts/ContractCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<img id="contract-thumbnail" src="@Contract.SupplierLogoImagePath" class="img-thumbnail img-fluid" data-bs-toggle="modal" data-bs-target="#@("id_" + Contract.Id)" @onclick="AddToRecentlyViewed"/>
<div class="card-body d-flex bd-highlight mb-3 d-flex align-items-center">
<h3 class="p-2 bd-highlight flex-grow-1" id="contract-name">@Contract.Name</h3>
<FavoriteButton @ref="_favoriteButton" Contract="@Contract" OnFavoriteChange="@FavoriteChange"></FavoriteButton>
<FavoriteButton @ref="_favoriteButton" Contract="@Contract" OnFavoriteChange="@((args)=> FavoriteChange(((Guid, bool))args))"></FavoriteButton>
</div>

</div>
Expand All @@ -37,7 +37,7 @@
/// Called when a contract has its favorite status changed.
/// </summary>
[Parameter]
public EventCallback<Contract> OnFavoriteChange { get; set; } = EventCallback<Contract>.Empty;
public EventCallback<(Guid, bool)> OnFavoriteChange { get; set; } = EventCallback<(Guid, bool)>.Empty;

private async Task AddToRecentlyViewed()
{
Expand All @@ -48,10 +48,9 @@
}
}

private async Task FavoriteChange(Contract contract)
private async Task FavoriteChange((Guid Id, bool IsFavorite)args)
pkasinski marked this conversation as resolved.
Show resolved Hide resolved
{
Contract = contract;
await OnFavoriteChange.InvokeAsync(contract);
await OnFavoriteChange.InvokeAsync(args);
}

}
48 changes: 35 additions & 13 deletions src/Client/Pages/Contracts/FavoriteButton.razor
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
@using Microsoft.AspNetCore.JsonPatch
@using Application.MessagePassing
@using Microsoft.AspNetCore.JsonPatch
@using Newtonsoft.Json
@using Domain.Contracts
@using System.Text
@inject HttpClient _http

<button class="btn ms-auto p-2 flex-shrink-0" @onclick="ChangeFavorite">
@if (Contract.IsFavorite)
<button class="btn ms-auto p-2 flex-shrink-0" id="Favorite-button" @onclick="ChangeFavorite">
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved
@if (isFavorite)
{
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart-fill" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z"/>
Expand All @@ -31,23 +32,44 @@
/// Called when a contract has its favorite status changed.
/// </summary>
[Parameter]
public EventCallback<Contract> OnFavoriteChange { get; set; } = EventCallback<Contract>.Empty;
public EventCallback<(Guid, bool)> OnFavoriteChange { get; set; } = EventCallback<(Guid, bool)>.Empty;

/// <summary>
/// The name of the currently logged in user.
/// </summary>
[CascadingParameter(Name = nameof(LoggedInUser))]
public string? LoggedInUser { get; set; }

/// <summary>
/// Whether the contract is marked as favorite.
/// </summary>
private bool isFavorite { get; set; }

protected override async void OnInitialized()
{
HttpResponseMessage response = await _http.GetAsync($"/api/v1/favorites/{LoggedInUser}/{Contract.Id}");
if (response.IsSuccessStatusCode)
{
isFavorite = true;
}
else
{
isFavorite = false;
}
await InvokeAsync(StateHasChanged);
base.OnInitialized();
}

private async Task ChangeFavorite()
{
var patchDocument = new JsonPatchDocument<Contract>();
patchDocument.Replace(contract => contract.IsFavorite, !Contract.IsFavorite);
var serializedDocument = JsonConvert.SerializeObject(patchDocument);
var content = new StringContent(serializedDocument, Encoding.UTF8, "application/json-patch+json");
SetFavoriteContract setFavorite = new() { UserName = LoggedInUser!, ContractId = Contract.Id, IsFavorite = !isFavorite };
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved
pkasinski marked this conversation as resolved.
Show resolved Hide resolved

var response = await _http.PatchAsync($"/api/v1/Contracts/{Contract.Id}", content);
HttpResponseMessage response = await _http.PostAsJsonAsync($"/api/v1/favorites", setFavorite);
if (response.IsSuccessStatusCode)
{
var contract = await response.Content.ReadFromJsonAsync<Contract>();
if (contract != null) Contract = contract;
isFavorite = !isFavorite;
await InvokeAsync(StateHasChanged);
await OnFavoriteChange.InvokeAsync(Contract);
await OnFavoriteChange.InvokeAsync((Contract.Id, isFavorite));
}
}

}
16 changes: 11 additions & 5 deletions src/Client/Pages/Dashboard/FavoriteCards.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<h3>Favoriter</h3>
<FetchData @ref="_dataFetcher"
TData="List<Contract>"
Url="/api/v1/Contracts/favorites"
Url=@($"/api/v1/favorites/{LoggedInUser}")
Context="contracts">
@{
var contractsList = contracts.ToList();
Expand All @@ -16,7 +16,7 @@
<div id="favorite-cards-container" class="d-flex flex-row justify-content-around flex-wrap">
@foreach (var contract in contractsList)
{
<ContractCard Contract=@contract OnFavoriteChange="OnFavoriteChange"/>
<ContractCard Contract=@contract OnFavoriteChange="@((args)=> OnFavoriteChange(((Guid, bool))args))"/>
}
</div>
}
Expand All @@ -34,10 +34,16 @@
@code {
private FetchData<List<Contract>> _dataFetcher = null!;

private async Task OnFavoriteChange(Contract contract)
/// <summary>
/// The name of the currently logged in user.
/// </summary>
[CascadingParameter(Name = nameof(LoggedInUser))]
public string? LoggedInUser { get; set; }

private async Task OnFavoriteChange((Guid Id, bool IsFavorite)args)
{
if (contract.IsFavorite) return;
_dataFetcher.Data?.RemoveAll(other => other.Id == contract.Id);
if (args.IsFavorite) return;
_dataFetcher.Data?.RemoveAll(other => other.Id == args.Id);
await InvokeAsync(StateHasChanged);
}

Expand Down
16 changes: 10 additions & 6 deletions src/Domain/Contracts/Contract.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Domain.Contracts;
using Domain.Users;

namespace Domain.Contracts;

/// <summary>
/// A document containing negotiated discounts and benefits.
Expand All @@ -10,11 +12,6 @@ public class Contract
/// </summary>
public Guid Id { get; init; } = Guid.NewGuid();

/// <summary>
/// Gets or sets a value indicating whether the contract is a favorite or not.
/// </summary>
public bool IsFavorite { get; set; }

/// <summary>
/// Gets or sets the name of the contract.
/// </summary>
Expand Down Expand Up @@ -69,4 +66,11 @@ public class Contract
/// Gets or sets the contact information for the supplier.
/// </summary>
public string SupplierContactInfo { get; set; } = "Kontaktinformation till leverantör saknas.";

/// <summary>
/// Gets or sets users that has marked this as favorite.
/// </summary>
#pragma warning disable CA2227 // Collection properties should be read only
public ICollection<User> Users { get; set; } = new List<User>();
#pragma warning restore CA2227 // Collection properties should be read only
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved
}
7 changes: 7 additions & 0 deletions src/Domain/Users/User.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Domain.Contracts;

namespace Domain.Users;

/// <summary>
Expand Down Expand Up @@ -34,4 +36,9 @@ public class User
/// Gets or sets the date of the latest payment by the user. It is set to 1/1/0001 12:00:00 AM by default.
/// </summary>
public DateTime LatestPaymentDate { get; set; } = DateTime.MinValue;

/// <summary>
/// Gets favorite contracts.
/// </summary>
public ICollection<Contract> Contracts { get; init; } = new List<Contract>();
JacobBredin marked this conversation as resolved.
Show resolved Hide resolved
}
3 changes: 0 additions & 3 deletions src/Infrastructure/Databases/EFContractRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ public EFContractRepository(EFDatabaseContext context, ILogger<EFContractReposit
/// <inheritdoc />
public IEnumerable<Contract> Recent => _recent.FetchRecentContracts();

/// <inheritdoc />
public IEnumerable<Contract> Favorites => Contracts.Where(contract => contract.IsFavorite);

private DbSet<Contract> Contracts => _context.Contracts;

/// <inheritdoc />
Expand Down
Loading