@page "/students/event-ranking-edit/{StudentId:int}" @attribute [Authorize] @using Microsoft.EntityFrameworkCore @using WebApp.Models @inject AppDbContext Context @inject NavigationManager NavigationManager @inject ISnackbar Snackbar @inject ILogger Logger @if (_student == null) {

Loading...

} else { Save Rankings
Ranked Events
Use the arrows to set rank. Use the X to remove an event. Up to @StudentEventRanking.MaxRank events.
@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)
}
Available Events
@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 { [Parameter] public int? StudentId { get; set; } private Student? _student; private List _rankedEvents = []; private List _availableEvents = []; private bool AtMaxRank => _rankedEvents.Count >= StudentEventRanking.MaxRank; protected override async Task OnInitializedAsync() { _student = await Context.Students .Include(e => e.EventRankings) .ThenInclude(r => r.EventDefinition) .Where(e => e.Id == StudentId) .FirstAsync(); var events = await Context.Events .OrderBy(e => e.Name) .ToListAsync(); _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 AddRanked(EventDefinition item) { if (AtMaxRank || _rankedEvents.Any(e => e.Id == item.Id)) { return; } _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() { if (_student == null) return; try { var uniqueRanked = _rankedEvents.DistinctBy(e => e.Id).Take(StudentEventRanking.MaxRank).ToList(); _student.EventRankings.Clear(); for (var index = 0; index < uniqueRanked.Count; index++) { var evt = uniqueRanked[index]; _student.EventRankings.Add(new StudentEventRanking { EventDefinition = evt, Student = _student, Rank = index + 1 }); } Context.Students.Update(_student); await Context.SaveChangesAsync(); Snackbar.Add($"Event rankings saved for {_student.Name}", Severity.Success); NavigationManager.NavigateTo("/students/event-ranking"); } catch (Exception e) { Snackbar.Add("Error saving rankings. Please try again.", Severity.Error); Logger.LogError(e, "Error saving event rankings for student {StudentId}", StudentId); } } }