Implement TeamMeetingToggleSelector component and extend team management functionality

This commit introduces the TeamMeetingToggleSelector component, which allows for the selection and management of teams within the meeting schedule. The Index.razor component has been updated to utilize this new selector, enhancing the user interface for managing scheduled and extended teams. Additionally, new methods for saving and loading extended teams have been added, improving the overall functionality and user experience in team scheduling. These changes contribute to better organization and management of team events in the application.
This commit is contained in:
2026-01-13 09:32:45 -05:00
parent f8c22690d4
commit 1601610226
2 changed files with 201 additions and 5 deletions
@@ -91,11 +91,13 @@
Label="Search for absent students"
ShowFullName="true"/>
<MudDivider Class="my-4"/>
<TeamToggleSelector Teams="@_teams"
SelectedTeams="_scheduledTeams"
SelectedTeamsChanged="OnScheduledTeamsChanged"
Title="Scheduled Teams"
ShowEventAttributes="true" />
<TeamMeetingToggleSelector Teams="@_teams"
SelectedTeams="_scheduledTeams"
SelectedTeamsChanged="OnScheduledTeamsChanged"
ExtendedTeams="_extendedTeams"
ExtendedTeamsChanged="OnExtendedTeamsChanged"
Title="Scheduled Teams"
ShowEventAttributes="false" />
</MudStack>
</MudItem>
@@ -112,6 +114,7 @@
private IEnumerable<Team> _scheduledTeams = [];
private IEnumerable<Student> _absentStudents = [];
private IEnumerable<Team> _possibleAdditions = [];
private IEnumerable<Team> _extendedTeams = [];
private async Task OnScheduledTeamsChanged(IEnumerable<Team> teams)
{
@@ -131,6 +134,12 @@
await SaveTimeSlotCount();
}
private async Task OnExtendedTeamsChanged(IEnumerable<Team> teams)
{
_extendedTeams = teams;
await SaveExtendedTeams();
}
private async void AddRegionals()
{
_scheduledTeams
@@ -240,6 +249,7 @@
await LoadScheduledTeams();
await LoadAbsentStudents();
await LoadTimeSlotCount();
await LoadExtendedTeams();
}
private async Task SaveScheduledTeams()
@@ -286,6 +296,21 @@
}
}
private async Task SaveExtendedTeams()
{
var teamIds = _extendedTeams.Select(t => t.Id).ToArray();
await LocalStorage.SetIntArrayAsync("MeetingSchedule_ExtendedTeams", teamIds);
}
private async Task LoadExtendedTeams()
{
var teamIds = await LocalStorage.GetIntArrayAsync("MeetingSchedule_ExtendedTeams");
if (teamIds.Length > 0)
{
_extendedTeams = _teams.Where(t => teamIds.Contains(t.Id)).ToArray();
}
}
private async Task<TableData<TeamScheduleTimeSlot>> SolveSchedule(TableState arg1, CancellationToken arg2)
{
_isSolving = true;
@@ -311,10 +336,22 @@
// Update parameters with absent student names
_parameters.AbsentStudents = _absentStudents.Select(s => s.FirstNameLastName).ToArray();
// Update parameters with extended team event names
_parameters.ExtendedTeams = _extendedTeams
.Where(t => t.Event != null)
.Select(t => t.Event!.Name)
.ToArray();
var teamScheduler = new TeamScheduler(_scheduledTeams, _parameters.TimeSlots, availableStudents);
_solution = teamScheduler.Solve();
// Post-process: extend teams to next consecutive time slot
if (_extendedTeams.Any())
{
ExtendTeamsInSolution(_solution, _extendedTeams, availableStudents);
}
// Try recommendation strategies in priority order
var scheduler = new UnassignedStudentScheduler(_teams, _solution.TimeSlots);
UnassignedScheduleStrategy[] strategies =
@@ -340,6 +377,57 @@
_solutionData.ReloadServerData();
}
private void ExtendTeamsInSolution(TeamSchedulerSolution solution, IEnumerable<Team> extendedTeams, Student[] allStudents)
{
if (solution.TimeSlots == null || !solution.TimeSlots.Any())
return;
var extendedTeamsList = extendedTeams.ToList();
if (!extendedTeamsList.Any())
return;
var extendedTeamIds = extendedTeamsList.Select(t => t.Id).ToHashSet();
// Find which time slot each extended team is in
for (int slotIndex = 0; slotIndex < solution.TimeSlots.Length; slotIndex++)
{
var currentSlot = solution.TimeSlots[slotIndex];
var teamsToExtend = currentSlot.Teams.Where(t => extendedTeamIds.Contains(t.Id)).ToList();
if (!teamsToExtend.Any())
continue;
// Check if there's a next time slot
if (slotIndex + 1 >= solution.TimeSlots.Length)
{
// Cannot extend - this is the last time slot
continue;
}
var nextSlot = solution.TimeSlots[slotIndex + 1];
// Add extended teams to the next time slot
var nextSlotTeamsList = nextSlot.Teams.ToList();
var nextSlotTeamIds = nextSlotTeamsList.Select(t => t.Id).ToHashSet();
foreach (var team in teamsToExtend)
{
if (!nextSlotTeamIds.Contains(team.Id))
{
nextSlotTeamsList.Add(team);
nextSlotTeamIds.Add(team.Id);
}
}
// Update the next slot with the extended teams
nextSlot.Teams = nextSlotTeamsList.ToArray();
// Recalculate overlaps and unscheduled students for the next slot
nextSlot.StudentOverlaps = TeamSchedulerSolution.GetStudentTeamOverlaps(nextSlot.Teams);
nextSlot.UnscheduledStudents = TeamSchedulerSolution.GetStudentsNotInTimSlot(nextSlot.Teams, allStudents);
}
}
async Task CopyToClipboard()
{
var sb = new StringBuilder();