diff --git a/WebApp/Components/App.razor b/WebApp/Components/App.razor index 63d504d..aec7b52 100644 --- a/WebApp/Components/App.razor +++ b/WebApp/Components/App.razor @@ -22,7 +22,6 @@ - diff --git a/WebApp/Components/Features/Students/EventRankingEdit.razor b/WebApp/Components/Features/Students/EventRankingEdit.razor index a7f047e..5e67582 100644 --- a/WebApp/Components/Features/Students/EventRankingEdit.razor +++ b/WebApp/Components/Features/Students/EventRankingEdit.razor @@ -1,9 +1,7 @@ @page "/students/event-ranking-edit/{StudentId:int}" @attribute [Authorize] @using Microsoft.EntityFrameworkCore -@using BlazorSortableList @using WebApp.Models -@using WebApp.Components.Shared.Components @inject AppDbContext Context @inject NavigationManager NavigationManager @inject ISnackbar Snackbar @@ -33,7 +31,6 @@ else - @* https://github.com/AlexNek/BlazorSortableList *@ @@ -41,29 +38,52 @@ else Ranked Events - Drag events here in order of preference + + Use the arrows to set rank. Use the X to remove an event. Up to @StudentEventRanking.MaxRank events. + - - - - -
- - - -
- @item.Name - - @AppIcons.EventAttributes(item) @AppIcons.EventEffort(item) - -
-
-
-
-
-
+ @if (_rankedEvents.Count == 0) + { + + No ranked events yet. Add events from the list on the right. + + } + @for (var i = 0; i < _rankedEvents.Count; i++) + { + var index = i; + var item = _rankedEvents[index]; + var rank = index + 1; + + +
+ + + +
+ @item.Name + + @AppIcons.EventAttributes(item) @AppIcons.EventEffort(item) + +
+ + + +
+
+
+ }
@@ -71,99 +91,117 @@ else Available Events - Drag events to rank them + + @if (AtMaxRank) + { + Maximum of @StudentEventRanking.MaxRank ranked events reached. Remove one to add another. + } + else + { + Use Add to place an event at the end of the ranked list. + } + - - - - + @if (_availableEvents.Count == 0) + { + + @(_rankedEvents.Count == 0 ? "No events are available to rank." : "All events are already ranked.") + + } + @foreach (var item in _availableEvents) + { + + +
+
@item.Name @AppIcons.EventAttributes(item) @AppIcons.EventEffort(item) - - - - +
+ +
+
+
+ }
} @code { - private const string ListId1 = "SharedListId1"; - private const string ListId2 = "SharedListId2"; - private const string GroupId = "CommonGroup"; - [Parameter] public int? StudentId { get; set; } private Student? _student; - private List? _events; - public List _rankedEvents = []; - public List _availableEvents = []; + private List _rankedEvents = []; + private List _availableEvents = []; - private void RankedEventsRemove((int oldIndex, int newIndex) indices) - { - // get the item at the old index in list 1 - var item = _rankedEvents[indices.oldIndex]; - - // add it to the new index in list 2 - _availableEvents.Insert(indices.newIndex, item); - - // remove the item from the old index in list 1 - _rankedEvents.Remove(_rankedEvents[indices.oldIndex]); - } - - private void AvailableEventsRemove((int oldIndex, int newIndex) indices) - { - // get the item at the old index in list 2 - var item = _availableEvents[indices.oldIndex]; - - // add it to the new index in list 1 - _rankedEvents.Insert(indices.newIndex, item); - - // remove the item from the old index in list 2 - _availableEvents.Remove(_availableEvents[indices.oldIndex]); - } + private bool AtMaxRank => _rankedEvents.Count >= StudentEventRanking.MaxRank; protected override async Task OnInitializedAsync() { _student = await Context.Students .Include(e => e.EventRankings) - .Where(e => e.Id == StudentId).FirstAsync(); - _events = + .ThenInclude(r => r.EventDefinition) + .Where(e => e.Id == StudentId) + .FirstAsync(); + + var events = await Context.Events .OrderBy(e => e.Name) - .ToListAsync(); + .ToListAsync(); - _rankedEvents = _student.EventRankings.OrderBy(e => e.Rank).Select(e => e.EventDefinition).ToList(); - _availableEvents = _events.Where(e => !_rankedEvents.Contains(e)).ToList(); + _rankedEvents = _student.EventRankings + .Where(e => e.EventDefinition != null) + .OrderBy(e => e.Rank) + .Select(e => e.EventDefinition) + .DistinctBy(e => e.Id) + .Take(StudentEventRanking.MaxRank) + .ToList(); + + var rankedIds = _rankedEvents.Select(e => e.Id).ToHashSet(); + _availableEvents = events.Where(e => !rankedIds.Contains(e.Id)).ToList(); } - private void Update((int oldIndex, int newIndex) indices) + private void AddRanked(EventDefinition item) { - var (oldIndex, newIndex) = indices; - - var items = _rankedEvents; - var itemToMove = items[oldIndex]; - items.RemoveAt(oldIndex); - - if (newIndex < items.Count) + if (AtMaxRank || _rankedEvents.Any(e => e.Id == item.Id)) { - items.Insert(newIndex, itemToMove); - } - else - { - items.Add(itemToMove); + return; } - StateHasChanged(); + _availableEvents.RemoveAll(e => e.Id == item.Id); + _rankedEvents.Add(item); } + private void RemoveRanked(EventDefinition item) + { + _rankedEvents.RemoveAll(e => e.Id == item.Id); + if (_availableEvents.All(e => e.Id != item.Id)) + { + _availableEvents.Add(item); + _availableEvents.Sort((left, right) => string.Compare(left.Name, right.Name, StringComparison.OrdinalIgnoreCase)); + } + } + + private void MoveRanked(EventDefinition item, int offset) + { + var index = _rankedEvents.FindIndex(e => e.Id == item.Id); + var newIndex = index + offset; + if (index < 0 || newIndex < 0 || newIndex >= _rankedEvents.Count) + { + return; + } + + _rankedEvents.RemoveAt(index); + _rankedEvents.Insert(newIndex, item); + } async Task Save() { @@ -172,10 +210,12 @@ else try { + var uniqueRanked = _rankedEvents.DistinctBy(e => e.Id).Take(StudentEventRanking.MaxRank).ToList(); + _student.EventRankings.Clear(); - for (var index = 0; index < _rankedEvents.Count; index++) + for (var index = 0; index < uniqueRanked.Count; index++) { - var evt = _rankedEvents[index]; + var evt = uniqueRanked[index]; _student.EventRankings.Add(new StudentEventRanking { EventDefinition = evt, diff --git a/WebApp/Models/SharedSortableListGroup.cs b/WebApp/Models/SharedSortableListGroup.cs deleted file mode 100644 index 9277c43..0000000 --- a/WebApp/Models/SharedSortableListGroup.cs +++ /dev/null @@ -1,16 +0,0 @@ -using BlazorSortableList; -using Core.Entities; - -namespace WebApp.Models; - -/// -/// Class SharedSortableListGroup. -/// Used for BlazorSortableList -/// -internal class SharedSortableListGroup : MultiSortableListGroup -{ - public SharedSortableListGroup(Action refreshComponent) - : base(refreshComponent) - { - } -} \ No newline at end of file diff --git a/WebApp/WebApp.csproj b/WebApp/WebApp.csproj index c3bb11c..f7caa43 100644 --- a/WebApp/WebApp.csproj +++ b/WebApp/WebApp.csproj @@ -13,7 +13,6 @@ -