feat: add optional student nickname for informal display
Keep legal first and last names for formal lists; show DisplayFirstName on teams, calendars, and import matching so two Josiahs can be told apart. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -222,7 +222,7 @@ else
|
||||
.ThenInclude(t => t!.Captain)
|
||||
.Include(s => s.Teams)
|
||||
.ThenInclude(t => t!.Students)
|
||||
.OrderBy(s => s.FirstName)
|
||||
.OrderBy(s => s.Nickname ?? s.FirstName)
|
||||
.ThenBy(s => s.LastName)
|
||||
.ToArrayAsync();
|
||||
}
|
||||
@@ -391,15 +391,15 @@ else
|
||||
|
||||
if (isIndividual)
|
||||
{
|
||||
var ordered = students.OrderBy(s => s.FirstName, StringComparer.OrdinalIgnoreCase);
|
||||
var ordered = students.OrderBy(s => s.DisplayFirstName, StringComparer.OrdinalIgnoreCase);
|
||||
return string.Join(", ", ordered.Select(s => FormatCombinedScheduleStudentSegment(s, team, isIndividual)));
|
||||
}
|
||||
|
||||
var cap = team.Captain;
|
||||
var capInRoster = cap != null && students.Exists(s => s.Id == cap.Id);
|
||||
IEnumerable<Student> orderedTeam = capInRoster
|
||||
? students.Where(s => s.Id != cap!.Id).OrderBy(s => s.FirstName, StringComparer.OrdinalIgnoreCase).Prepend(cap!)
|
||||
: students.OrderBy(s => s.FirstName, StringComparer.OrdinalIgnoreCase);
|
||||
? students.Where(s => s.Id != cap!.Id).OrderBy(s => s.DisplayFirstName, StringComparer.OrdinalIgnoreCase).Prepend(cap!)
|
||||
: students.OrderBy(s => s.DisplayFirstName, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return string.Join(", ", orderedTeam.Select(s => FormatCombinedScheduleStudentSegment(s, team, isIndividual)));
|
||||
}
|
||||
@@ -410,12 +410,12 @@ else
|
||||
{
|
||||
var sid = student.StateId?.Trim();
|
||||
return !string.IsNullOrEmpty(sid)
|
||||
? $"{student.FirstName} ({sid})"
|
||||
: student.FirstName;
|
||||
? $"{student.DisplayFirstName} ({sid})"
|
||||
: student.DisplayFirstName;
|
||||
}
|
||||
|
||||
var isCpt = team.Captain?.Id == student.Id;
|
||||
return isCpt ? $"{student.FirstName} (Cpt.)" : student.FirstName;
|
||||
return isCpt ? $"{student.DisplayFirstName} (Cpt.)" : student.DisplayFirstName;
|
||||
}
|
||||
|
||||
private sealed record EventSummaryRow(string StateRegistrationId, string EventName, string Activity);
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<MudStack Row="true" Spacing="1" Wrap="Wrap.Wrap">
|
||||
@{
|
||||
var presentStudentIds = _meetingHistory.Students.Select(s => s.Id).ToHashSet();
|
||||
var allStudents = GetAllStudentsFromTeams().OrderBy(s => s.FirstName);
|
||||
var allStudents = GetAllStudentsFromTeams().OrderBy(s => s.DisplayFirstName);
|
||||
}
|
||||
@foreach (var student in allStudents)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Label="@Label"
|
||||
@bind-Value="_currentStudent"
|
||||
SearchFunc="@SearchStudents"
|
||||
ToStringFunc="@(s => ShowFullName ? s?.FirstNameLastName : s?.FirstName)"
|
||||
ToStringFunc="@(s => ShowFullName ? s?.FirstNameLastName : s?.DisplayFirstName)"
|
||||
Immediate="true"
|
||||
ResetValueOnEmptyText="true"
|
||||
CoerceText="false"
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@student.FirstName
|
||||
@student.DisplayFirstName
|
||||
}
|
||||
@if (ShowGrade)
|
||||
{
|
||||
@@ -33,11 +33,11 @@
|
||||
@if (SelectedStudents.Any())
|
||||
{
|
||||
<MudChipSet T="Student" AllClosable="true" Class="mt-2">
|
||||
@foreach (var student in SelectedStudents.OrderBy(s => s.FirstName))
|
||||
@foreach (var student in SelectedStudents.OrderBy(s => s.DisplayFirstName))
|
||||
{
|
||||
<MudChip T="Student"
|
||||
Value="@student"
|
||||
Text="@(ShowFullName ? student.FirstNameLastName : student.FirstName)"
|
||||
Text="@(ShowFullName ? student.FirstNameLastName : student.DisplayFirstName)"
|
||||
OnClose="@(() => RemoveStudent(student))" />
|
||||
}
|
||||
</MudChipSet>
|
||||
@@ -91,8 +91,9 @@
|
||||
return Task.FromResult<IEnumerable<Student>>(Students
|
||||
.Where(s => !SelectedStudents.Contains(s))
|
||||
.Where(s => s.FirstName.ToLower().Contains(search) ||
|
||||
s.LastName.ToLower().Contains(search))
|
||||
.OrderBy(s => s.FirstName));
|
||||
s.LastName.ToLower().Contains(search) ||
|
||||
(s.Nickname != null && s.Nickname.ToLower().Contains(search)))
|
||||
.OrderBy(s => s.DisplayFirstName));
|
||||
}
|
||||
|
||||
private void RemoveStudent(Student student)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
ValuesChanged="@OnSelectedStudentsChanged"
|
||||
Vertical="true"
|
||||
CheckMark>
|
||||
@foreach (var student in Students.OrderBy(e => e.FirstName))
|
||||
@foreach (var student in Students.OrderBy(e => e.DisplayFirstName))
|
||||
{
|
||||
<MudToggleItem Value="@student" Style="font-size: .75rem;">
|
||||
@if (ShowFullName)
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@student.FirstName
|
||||
@student.DisplayFirstName
|
||||
}
|
||||
</MudToggleItem>
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudTextField T="string" Label="Last Name" @bind-Value="Student.LastName" For="@(() => Student.LastName)" Variant="Variant.Outlined"></MudTextField>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudTextField T="string" Label="Nickname" @bind-Value="Student.Nickname" For="@(() => Student.Nickname)" Variant="Variant.Outlined" HelperText="Shown instead of first name on teams, rankings, and printouts"></MudTextField>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudTextField T="string" Label="Email Address" @bind-Value="Student.Email" For="@(() => Student.Email)" Variant="Variant.Outlined"></MudTextField>
|
||||
</MudItem>
|
||||
@@ -80,6 +83,7 @@
|
||||
|
||||
try
|
||||
{
|
||||
Student.NormalizeNickname();
|
||||
Context.Students.Add(Student);
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">Last Name</MudText>
|
||||
<MudText Typo="Typo.body1">@student.LastName</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">Nickname</MudText>
|
||||
<MudText Typo="Typo.body1">@(string.IsNullOrWhiteSpace(student.Nickname) ? "—" : student.Nickname)</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">Grade</MudText>
|
||||
<MudText Typo="Typo.body1">@student.Grade</MudText>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<MudPaper Elevation="2" Class="pa-3 pa-md-6">
|
||||
<MudTextField T="string" Label="First Name" @bind-Value="Student.FirstName" For="@(() => Student.FirstName)"></MudTextField>
|
||||
<MudTextField T="string" Label="Last Name" @bind-Value="Student.LastName" For="@(() => Student.LastName)"></MudTextField>
|
||||
<MudTextField T="string" Label="Nickname" @bind-Value="Student.Nickname" For="@(() => Student.Nickname)" HelperText="Shown instead of first name on teams, rankings, and printouts"></MudTextField>
|
||||
<MudTextField T="string" Label="Email Adress" @bind-Value="Student.Email" For="@(() => Student.Email)"></MudTextField>
|
||||
<MudTextField T="string" Label="Phone Number" @bind-Value="Student.PhoneNumber" For="@(() => Student.PhoneNumber)"></MudTextField>
|
||||
<MudTextField T="int" Label="Grade" @bind-Value="Student.Grade" For="@(() => Student.Grade)"></MudTextField>
|
||||
@@ -121,7 +122,8 @@
|
||||
if (Student?.OfficerRole == 0)
|
||||
Student.OfficerRole = null;
|
||||
|
||||
Context.Attach(Student!).State = EntityState.Modified;
|
||||
Student!.NormalizeNickname();
|
||||
Context.Attach(Student).State = EntityState.Modified;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -67,6 +67,10 @@
|
||||
Color="Color.Primary">
|
||||
@context.Item.LastNameFirstName
|
||||
</MudLink>
|
||||
@if (!string.IsNullOrWhiteSpace(context.Item.Nickname))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@context.Item.Nickname</MudText>
|
||||
}
|
||||
@if (context.Item.OfficerRole != null)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Icon="@(AppIcons.OfficerRoleIcon(context.Item.OfficerRole.Value))">@context.Item.OfficerRole</MudChip>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Value="@SelectedCaptain"
|
||||
ValueChanged="@OnSelectedCaptainChanged"
|
||||
CheckMark>
|
||||
@foreach (var student in Students.OrderBy(e => e.FirstName))
|
||||
@foreach (var student in Students.OrderBy(e => e.DisplayFirstName))
|
||||
{
|
||||
<MudToggleItem Value="@student" Text="@student.Name" />
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
{
|
||||
// For individual events, use student's first name as identifier
|
||||
var student = _selectedStudents.First();
|
||||
Team.Identifier = student.FirstName;
|
||||
Team.Identifier = student.DisplayFirstName;
|
||||
Team.Captain = student;
|
||||
}
|
||||
else if (existingTeamCount == 1)
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
{
|
||||
case EventFormat.Individual when Team.Students.Count == 1:
|
||||
Team.Captain ??= Team.Students[0];
|
||||
Team.Identifier ??= Team.Captain.FirstName;
|
||||
Team.Identifier ??= Team.Captain.DisplayFirstName;
|
||||
break;
|
||||
case EventFormat.Team:
|
||||
break;
|
||||
@@ -134,7 +134,7 @@
|
||||
if (Team is { Event.EventFormat: EventFormat.Individual, Students.Count: 1 })
|
||||
{
|
||||
Team.Captain ??= Team.Students[0];
|
||||
Team.Identifier = Team.Captain.FirstName;
|
||||
Team.Identifier = Team.Captain.DisplayFirstName;
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
@@ -72,7 +72,7 @@ else
|
||||
.ThenInclude(e => e.Event)
|
||||
.Include(e => e.Teams)
|
||||
.ThenInclude(e => e.Students)
|
||||
.OrderBy(e => e.FirstName)
|
||||
.OrderBy(e => e.Nickname ?? e.FirstName)
|
||||
.ToArrayAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,6 @@ else
|
||||
.ThenInclude(e => e.Captain)
|
||||
.Include(e => e.EventRankings)
|
||||
.ThenInclude(e => e.EventDefinition)
|
||||
.OrderBy(e => e.FirstName).ToArrayAsync();
|
||||
.OrderBy(e => e.Nickname ?? e.FirstName).ToArrayAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user