52bf303537
This commit introduces functionality in the MeetingSchedule feature to manage student exclusions during scheduling. The Index.razor component has been updated to include methods for saving and loading excluded students, as well as UI elements for toggling exclusions. Additionally, the TeamScheduler logic has been modified to account for excluded students when calculating overlaps and scheduling teams. These changes improve the flexibility and accuracy of the scheduling process, enhancing the overall user experience.
128 lines
5.6 KiB
Plaintext
128 lines
5.6 KiB
Plaintext
@using Core.Calculation
|
|
@using WebApp.Models
|
|
@using Core.Utility
|
|
|
|
<MudStack>
|
|
<MudText Typo="Typo.h6">@TimeSlotName</MudText>
|
|
@foreach (var team in Teams.OrderByEventFormatFirst().ThenBy(e => e.ToString()))
|
|
{
|
|
var scheduledTeamIds = ScheduledTeams.Select(t => t.Id).ToHashSet();
|
|
var removed = !scheduledTeamIds.Contains(team.Id);
|
|
|
|
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Class="d-flex align-center">
|
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
|
<MudIcon Icon="@Icons.Material.Filled.Clear"
|
|
Size="Size.Small"
|
|
Class="@(removed ? "" : "d-none")"
|
|
OnClick="@(() => OnToggleTeam.InvokeAsync(team))"
|
|
Style="cursor: pointer;">
|
|
</MudIcon>
|
|
@{
|
|
var teamMembers = TeamStudentNameFormatter.FormatStudentList(
|
|
team,
|
|
new TeamStudentNameFormatter.FormatOptions
|
|
{
|
|
Ordering = TeamStudentNameFormatter.OrderingStyle.None
|
|
});
|
|
}
|
|
<MudTooltip Text="@teamMembers">
|
|
<div @onclick="@(() => OnToggleTeam.InvokeAsync(team))" style="cursor: pointer; display: inline-block;">
|
|
<MudChip T="string"
|
|
Size="Size.Small"
|
|
Color="Color.Default">
|
|
@team
|
|
</MudChip>
|
|
</div>
|
|
</MudTooltip>
|
|
</MudStack>
|
|
<MudStack Row="true" Spacing="1" Wrap="Wrap.Wrap" AlignItems="AlignItems.Center">
|
|
@{
|
|
var nonExcludedStudentCount = GetNonExcludedStudentCount(team);
|
|
}
|
|
@foreach (var student in team.Students)
|
|
{
|
|
var overlap = StudentHasOverlaps(student);
|
|
var chipColor = overlap ? Color.Warning : Color.Default;
|
|
var isExcluded = IsStudentExcluded(team.Id, TimeSlotIndex, student.Id);
|
|
var formattedName = TeamStudentNameFormatter.FormatStudentName(
|
|
student,
|
|
team,
|
|
new TeamStudentNameFormatter.FormatOptions
|
|
{
|
|
MarkOverlaps = true,
|
|
HasOverlaps = StudentHasOverlaps,
|
|
MarkAbsent = true,
|
|
AbsentStudents = AbsentStudents.ToList()
|
|
});
|
|
|
|
<MudStack Row="true" Spacing="0" AlignItems="AlignItems.Center"
|
|
Style="position: relative; display: inline-flex;"
|
|
@onmouseenter="@(() => _hoveredStudent = (team.Id, student.Id))"
|
|
@onmouseleave="@(() => _hoveredStudent = (null, null))">
|
|
<MudChip T="string"
|
|
Size="Size.Small"
|
|
Color="@chipColor"
|
|
Variant="Variant.Outlined"
|
|
Style="@(isExcluded ? "opacity: 0.5;" : "")">
|
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
|
<span>@formattedName</span>
|
|
@if (_hoveredStudent == (team.Id, student.Id) && nonExcludedStudentCount > 1)
|
|
{
|
|
<MudIconButton Icon="@Icons.Material.Filled.Close"
|
|
Size="Size.Small"
|
|
Color="Color.Error"
|
|
Variant="Variant.Text"
|
|
OnClick="@(() => OnToggleStudentExclusion.InvokeAsync((team.Id, TimeSlotIndex, student.Id)))"
|
|
Style="padding: 0; min-width: 16px; width: 16px; height: 16px; margin-left: 4px;" />
|
|
}
|
|
</MudStack>
|
|
</MudChip>
|
|
</MudStack>
|
|
}
|
|
</MudStack>
|
|
</MudStack>
|
|
}
|
|
</MudStack>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public string TimeSlotName { get; set; } = string.Empty;
|
|
|
|
[Parameter]
|
|
public int TimeSlotIndex { get; set; }
|
|
|
|
[Parameter]
|
|
public IEnumerable<Team> Teams { get; set; } = [];
|
|
|
|
[Parameter]
|
|
public IEnumerable<Team> ScheduledTeams { get; set; } = [];
|
|
|
|
[Parameter]
|
|
public IEnumerable<Student> AbsentStudents { get; set; } = [];
|
|
|
|
[Parameter]
|
|
public Func<Student, bool> StudentHasOverlaps { get; set; } = null!;
|
|
|
|
[Parameter]
|
|
public Dictionary<(int teamId, int timeSlotIndex, int studentId), bool> ExcludedStudents { get; set; } = new();
|
|
|
|
[Parameter]
|
|
public EventCallback<Team> OnToggleTeam { get; set; }
|
|
|
|
[Parameter]
|
|
public EventCallback<(int teamId, int timeSlotIndex, int studentId)> OnToggleStudentExclusion { get; set; }
|
|
|
|
private (int? teamId, int? studentId) _hoveredStudent = (null, null);
|
|
|
|
private bool IsStudentExcluded(int teamId, int timeSlotIndex, int studentId)
|
|
{
|
|
var key = (teamId, timeSlotIndex, studentId);
|
|
return ExcludedStudents.ContainsKey(key) && ExcludedStudents[key];
|
|
}
|
|
|
|
private int GetNonExcludedStudentCount(Team team)
|
|
{
|
|
return team.Students.Count(s => !IsStudentExcluded(team.Id, TimeSlotIndex, s.Id));
|
|
}
|
|
}
|