Refactor Teams components for improved sorting and filtering functionality

Updated the Teams Index and Printout components to prioritize sorting by EventFormat, enhancing the organization of team data. Introduced a regional filter toggle in the Teams Index to allow users to view only regional teams. Adjusted the ScheduledTeamsList to sort teams by EventFormat first, ensuring consistent ordering across components. Additionally, added necessary using directives for improved code clarity.
This commit is contained in:
2026-01-04 14:56:28 -05:00
parent c6fb00c7f4
commit 83522ac52c
7 changed files with 150 additions and 19 deletions
@@ -52,19 +52,18 @@
<EventAttributes EventDefinition="context.Item"></EventAttributes>
</CellTemplate>
</TemplateColumn>
<PropertyColumn Property="@(e => e.EventFormat)" Title="Event Format" />
<TemplateColumn Title="Team Size" CellStyle="white-space:nowrap">
<CellTemplate>
<MudTooltip Text="@context.Item.Eligibility">
[@context.Item.MinTeamSize&nbsp;-&nbsp;@context.Item.MaxTeamSize]
[@context.Item.MinTeamSize&nbsp;-&nbsp;@context.Item.MaxTeamSize]
</MudTooltip>
</CellTemplate>
</TemplateColumn>
<PropertyColumn Property="@(e => e.ChapterEligibilityCountState)" Title="State#" />
<PropertyColumn Property="@(e => e.LevelOfEffort)" Title="Level of Effort" />
<PropertyColumn Property="@(e => e.EventFormat)" Title="Event Format" />
</Columns>
<PagerContent>
<MudDataGridPager T="EventDefinition"></MudDataGridPager>
@@ -1,8 +1,9 @@
@using Core.Calculation
@using WebApp.Models
<MudStack>
<MudText Typo="Typo.h6">@TimeSlotName</MudText>
@foreach (var team in Teams.OrderBy(e => e.ToString()))
@foreach (var team in Teams.OrderByEventFormatFirst().ThenBy(e => e.ToString()))
{
var removed = !ScheduledTeams.Contains(team);
@@ -1,3 +1,5 @@
@using WebApp.Models
@if (Title != null)
{
<MudText Typo="Typo.h4">@Title</MudText>
@@ -9,7 +11,7 @@
ValuesChanged="@OnSelectedTeamsChanged"
Vertical="true"
CheckMark>
@foreach (var team in Teams.OrderBy(e => e.Event.Name))
@foreach (var team in Teams.OrderByEventFormatFirst().ThenBy(e => e.Event.Name))
{
<MudToggleItem Value="@team" Style="font-size: .75rem;">
<MudTooltip Text="@team.StudentsFirstNames">
+91 -10
View File
@@ -1,5 +1,6 @@
@using Microsoft.EntityFrameworkCore
@using WebApp.Components.Shared.Components
@using WebApp.Models
@page "/teams"
@attribute [Authorize]
@inject AppDbContext Context
@@ -9,9 +10,14 @@
<PageHeader Title="Teams">
<ActionButtons>
<MudButton StartIcon="@Icons.Material.Filled.Create" Href="teams/create" Variant="Variant.Filled" Color="Color.Primary">Create New</MudButton>
<MudButton StartIcon="@Icons.Material.Filled.Assignment" Href="teams/assignment" Variant="Variant.Outlined">Assignment</MudButton>
<MudButton StartIcon="@Icons.Material.Filled.Print" Href="teams/printout" Variant="Variant.Outlined">Printout</MudButton>
<MudButton StartIcon="@Icons.Material.Filled.Print" Href="teams/handout" Variant="Variant.Outlined">Handout</MudButton>
<MudButton StartIcon="@Icons.Material.Filled.FilterAlt"
Variant="@(_showRegionalOnly ? Variant.Filled : Variant.Outlined)"
Color="Color.Primary"
OnClick="ToggleRegionalFilter">
@(_showRegionalOnly ? "Showing Regional Only" : "Show Regional Only")
</MudButton>
</ActionButtons>
</PageHeader>
@@ -20,7 +26,7 @@
ServerData="ServerReload"
@ref="_dataGrid"
Filterable="true"
RowsPerPage="35"
RowsPerPage="50"
Dense="true"
Striped="true"
Hover="true"
@@ -67,24 +73,99 @@
@code {
MudDataGrid<Team> _dataGrid = null!;
private bool _isLoading = true;
private bool _showRegionalOnly = false;
private async Task ToggleRegionalFilter()
{
try
{
_showRegionalOnly = !_showRegionalOnly;
if (_dataGrid != null)
{
await _dataGrid.ReloadServerData();
}
}
catch (Exception ex)
{
Snackbar.Add($"Error applying filter: {ex.Message}", Severity.Error);
}
}
private async Task<GridData<Team>> ServerReload(GridState<Team> state)
{
_isLoading = true;
try
{
var query
IQueryable<Team> query
= Context.Teams
.Include(e => e.Event)
.Include(e => e.Students)
.ThenInclude(e => e.EventRankings)
.OrderBy(e => e.Event.Name)
.ThenBy(e => e.Identifier)
.Where(state.FilterDefinitions)
.OrderBy(state.SortDefinitions);
.ThenInclude(e => e.EventRankings);
var totalItems = await query.CountAsync();
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync();
// Apply regional filter if enabled
// Note: RegionalEvent is a computed property, so we must use the underlying property
if (_showRegionalOnly)
{
query = query.Where(t => t.Event.ChapterEligibilityCountRegionals > 0);
}
// Apply grid filter definitions
query = query.Where(state.FilterDefinitions);
// Load all data first
var allTeams = await query.ToArrayAsync();
// Always sort by EventFormat FIRST to separate group/individual teams
// Sort in memory to ensure this ordering is maintained regardless of user sorts
var sortedTeams = allTeams.OrderByEventFormatFirst();
// Apply user sort definitions as secondary sorts (within each group)
bool appliedUserSort = false;
if (state.SortDefinitions != null && state.SortDefinitions.Any())
{
var sortDef = state.SortDefinitions.First();
var sortBy = sortDef.SortBy ?? "";
// Handle Event.Name sorting
if (sortBy == "Event.Name" || (sortBy.Contains("Event") && sortBy.Contains("Name")))
{
sortedTeams = sortDef.Descending
? sortedTeams.ThenByDescending(t => t.Event.Name)
: sortedTeams.ThenBy(t => t.Event.Name);
appliedUserSort = true;
}
// Handle Identifier sorting
else if (sortBy == "Identifier")
{
sortedTeams = sortDef.Descending
? sortedTeams.ThenByDescending(t => t.Identifier ?? "")
: sortedTeams.ThenBy(t => t.Identifier ?? "");
appliedUserSort = true;
}
}
// Apply default secondary sorting
if (!appliedUserSort)
{
sortedTeams = sortedTeams
.ThenBy(t => t.Event.Name)
.ThenBy(t => t.Identifier ?? "");
}
else
{
// Add default sorting as tie-breakers
if (state.SortDefinitions?.First().SortBy != "Event.Name")
{
sortedTeams = sortedTeams.ThenBy(t => t.Event.Name);
}
if (state.SortDefinitions?.First().SortBy != "Identifier")
{
sortedTeams = sortedTeams.ThenBy(t => t.Identifier ?? "");
}
}
var totalItems = sortedTeams.Count();
var pagedData = sortedTeams.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArray();
return new GridData<Team>
{
@@ -220,8 +220,9 @@ else
= await Context.Teams
.Include(e => e.Event)
.Include(e => e.Students)
.OrderBy(e => e.Event.Name)
.ThenBy(e => e.Identifier)
.OrderByEventFormatFirst()
.ThenBy(e => e.Event.Name)
.ThenBy(e => e.Identifier ?? "")
.ToArrayAsync();
_maxTeamSize = _teams.Max(t => t.Students.Count);