Skip to content

Commit

Permalink
Merge pull request #39 from SSchulze1989/feature/color-coding-reviews
Browse files Browse the repository at this point in the history
Feature/color coding reviews
  • Loading branch information
SSchulze1989 authored Feb 12, 2023
2 parents f451c4b + b9e8d19 commit dc54919
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 9 deletions.
32 changes: 29 additions & 3 deletions src/iRLeagueManager.Web/Components/Reviews/ReviewCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
@inject NavigationManager NavigationManager

<CascadingValue Value=Review.InvolvedMembers>
<div @attributes=AdditionalAttributes class="card @AddCssClass @(Selected ? "border-info" : "")" id="[email protected]" @ref=Card>
<div class="card-header accordion-header review-header">
<div @attributes=AdditionalAttributes class="card @AddCssClass @GetBorderClass(Selected, Bind(Review, x => x.Status))" id="[email protected]" @ref=Card>
<div class="card-header accordion-header review-header @GetBorderClass(Selected, Bind(Review, x => x.Status))">
<div class="row">
<div class="col d-md-flex justify-content-start">
<span>@Review.SessionName:</span>
Expand Down Expand Up @@ -143,7 +143,7 @@
{
<li class="list-group-item">
<ReviewComment Comment=comment
OnStateHasChanged=@(() => InvokeAsync(StateHasChanged))
OnStateHasChanged=@(() => CommentStateChanged(comment))
OnDeleteClick=@(() => DeleteCommentClick(comment))/>
</li>
}
Expand Down Expand Up @@ -276,6 +276,32 @@
}
}

private async Task CommentStateChanged(ReviewCommentViewModel comment)
{
Review.UpdateReviewStatus();
await InvokeAsync(StateHasChanged);
}

private string GetBorderClass(bool selected, ReviewStatus status)
{
if (selected)
{
return "border-info";
}
switch(status)
{
case ReviewStatus.Open:
return "border-warning";
case ReviewStatus.Closed:
return "border-success";
case ReviewStatus.OpenConflicted:
return "border-warning";
case ReviewStatus.OpenEnoughVotes:
return "border-primary";
}
return "";
}

private async Task CopyDirectLink()
{
var url = NavigationManager.GetUriWithQueryParameter("reviewId", Review.ReviewId);
Expand Down
10 changes: 10 additions & 0 deletions src/iRLeagueManager.Web/Shared/ReviewStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace iRLeagueManager.Web.Shared;

public enum ReviewStatus
{
Open = 0,
OpenConflicted = 1,
OpenEnoughVotes = 2,
Closed = 3,
Overdue = 4,
}
69 changes: 65 additions & 4 deletions src/iRLeagueManager.Web/ViewModels/ReviewViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using iRLeagueApiCore.Common.Models.Reviews;
using iRLeagueManager.Web.Data;
using iRLeagueManager.Web.Extensions;
using iRLeagueManager.Web.Shared;
using System.IO.IsolatedStorage;

namespace iRLeagueManager.Web.ViewModels;

Expand Down Expand Up @@ -41,29 +43,35 @@ public ReviewViewModel(ILoggerFactory loggerFactory, LeagueApiService apiService
public IList<MemberInfoModel> InvolvedMembers { get => involvedMembers; set => Set(ref involvedMembers, value); }

private ObservableCollection<ReviewCommentViewModel> comments = new();
public ObservableCollection<ReviewCommentViewModel> Comments { get => comments; set => Set(ref comments, value); }
public ReadOnlyObservableCollection<ReviewCommentViewModel> Comments => new(comments);

private ObservableCollection<VoteViewModel> votes = new();
public ObservableCollection<VoteViewModel> Votes { get => votes; set => Set(ref votes, value); }

private ReviewStatus status;
public ReviewStatus Status { get => status; set => Set(ref status, value); }

public IEnumerable<CountedVote> CountedVotes => GetCountedVotes();

public void AddVote(VoteViewModel vote)
{
votes.Add(vote);
model.VoteResults.Add(vote.GetModel());
UpdateReviewStatus();
}

public void AddVote(VoteModel vote)
{
model.VoteResults.Add(vote);
votes.Add(new(LoggerFactory, ApiService, vote));
UpdateReviewStatus();
}

public void RemoveVote(VoteViewModel vote)
{
votes.Remove(vote);
model.VoteResults.Remove(vote.GetModel());
UpdateReviewStatus();
}

/// <summary>
Expand Down Expand Up @@ -229,19 +237,21 @@ private void RefreshCommentList()
// Add comments from to list that are not already in there
foreach (var comment in model.ReviewComments)
{
if (Comments.Any(x => x.GetModel() == comment) == false)
if (comments.Any(x => x.GetModel() == comment) == false)
{
Comments.Add(new ReviewCommentViewModel(LoggerFactory, ApiService, comment));
var commentViewModel = new ReviewCommentViewModel(LoggerFactory, ApiService, comment);
comments.Add(commentViewModel);
}
}
// Remove comments that are no longer in the model
foreach (var commentViewModel in Comments.ToArray())
{
if (model.ReviewComments.Any(x => x == commentViewModel.GetModel()) == false)
{
Comments.Remove(commentViewModel);
comments.Remove(commentViewModel);
}
}
UpdateReviewStatus();
}

public async Task<StatusResult> SaveChangesAsync(CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -314,6 +324,56 @@ private IEnumerable<CountedVote> GetCountedVotes()
return countedVotes;
}

public void UpdateReviewStatus()
{
if (IsClosed())
{
Status = ReviewStatus.Closed;
return;
}
if (IsVoteConflicted())
{
Status = ReviewStatus.OpenConflicted;
return;
}
if (HasMajorityVote(2))
{
Status = ReviewStatus.OpenEnoughVotes;
return;
}

Status = ReviewStatus.Open;
}

private bool IsClosed()
{
return Votes.Count > 0;
}

private bool IsVoteConflicted()
{
var votes = Comments
.Select(x => x.Votes.Select(y => y.GetModel()))
.ToList();
bool hasConflict = false;
for (int i=0; i<votes.Count-1; i++)
{
hasConflict |= !CompareVotes(votes[i], votes[i + 1]);
}
return hasConflict;
}

private bool CompareVotes(IEnumerable<VoteModel> first, IEnumerable<VoteModel> second)
{
return first.OrderBy(x => x.MemberAtFault?.MemberId).Zip(second.OrderBy(x => x.MemberAtFault?.MemberId))
.All(x => x.First.VoteCategoryId == x.Second.VoteCategoryId);
}

private bool HasMajorityVote(int minVoteCount)
{
return Comments.Count(x => x.Votes.Any()) >= minVoteCount;
}

private bool CompareVotes(VoteViewModel vote1, VoteViewModel vote2)
{
return vote1.MemberAtFault?.MemberId == vote2.MemberAtFault?.MemberId && vote1.VoteCategoryId == vote2.VoteCategoryId;
Expand Down Expand Up @@ -389,6 +449,7 @@ public override void SetModel(ReviewModel model)
RefreshMemberList();
RefreshCommentList();
RefreshVoteList();
UpdateReviewStatus();
SessionId = model.SessionId;
}
}
4 changes: 2 additions & 2 deletions src/iRLeagueManager.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
}
},
"AllowedHosts": "*",
"APIServer": "http://localhost:5000",
//"APIServer": "https://irleaguemanager.net/api/",
//"APIServer": "http://localhost:5000",
"APIServer": "https://irleaguemanager.net/api/",
"DefaultUser": "testuser",
"DefaultPassword": "TestPass123!"
}

0 comments on commit dc54919

Please sign in to comment.