Refactor UI components to utilize MudBlazor's layout system
This commit updates several components to replace traditional HTML layout elements with MudBlazor's MudStack component for improved styling and responsiveness. Changes include the CareerMapping.razor, Index.razor, Registration.razor, TeamStudents.razor, and TeamToggleSelector.razor files. These modifications enhance the visual consistency and maintainability of the UI by adhering to the project's design standards.
This commit is contained in:
@@ -38,6 +38,10 @@ else
|
|||||||
Click on a node to see details. Use mouse to zoom and pan the graph.
|
Click on a node to see details. Use mouse to zoom and pan the graph.
|
||||||
</MudText>
|
</MudText>
|
||||||
|
|
||||||
|
<div style="width: 100%; height: 600px; border: 1px solid #ddd; border-radius: 4px;">
|
||||||
|
<Network Id="careerMappingNetwork" Data="@_networkData" Options="@GetNetworkOptions" OnClick="HandleNetworkClick" />
|
||||||
|
</div>
|
||||||
|
|
||||||
@if (_selectedNodeInfo != null)
|
@if (_selectedNodeInfo != null)
|
||||||
{
|
{
|
||||||
<MudPaper Elevation="1" Class="pa-4 mb-4" Style="background-color: #f5f5f5;">
|
<MudPaper Elevation="1" Class="pa-4 mb-4" Style="background-color: #f5f5f5;">
|
||||||
@@ -61,9 +65,6 @@ else
|
|||||||
</MudPaper>
|
</MudPaper>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div style="width: 100%; height: 600px; border: 1px solid #ddd; border-radius: 4px;">
|
|
||||||
<Network Id="careerMappingNetwork" Data="@_networkData" Options="@GetNetworkOptions" OnClick="HandleNetworkClick"/>
|
|
||||||
</div>
|
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<PropertyColumn Property="@(e => e.LastName)" Title="Name" Sortable="true">
|
<PropertyColumn Property="@(e => e.LastName)" Title="Name" Sortable="true">
|
||||||
<CellTemplate>
|
<CellTemplate>
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="1">
|
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="1">
|
||||||
<div class="d-flex align-center flex-wrap" style="gap: 0.25rem;">
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Wrap="Wrap.Wrap">
|
||||||
<MudLink Href="@($"/students/details?id={context.Item.Id}&returnUrl=/students")"
|
<MudLink Href="@($"/students/details?id={context.Item.Id}&returnUrl=/students")"
|
||||||
Underline="Underline.Hover"
|
Underline="Underline.Hover"
|
||||||
Color="Color.Primary">
|
Color="Color.Primary">
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
{
|
{
|
||||||
<MudChip T="string" Size="Size.Small" Icon="@(AppIcons.OfficerRoleIcon(context.Item.OfficerRole.Value))">@context.Item.OfficerRole</MudChip>
|
<MudChip T="string" Size="Size.Small" Icon="@(AppIcons.OfficerRoleIcon(context.Item.OfficerRole.Value))">@context.Item.OfficerRole</MudChip>
|
||||||
}
|
}
|
||||||
</div>
|
</MudStack>
|
||||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
||||||
<IconButtonWithTooltip Icon="@Icons.Material.Filled.Edit"
|
<IconButtonWithTooltip Icon="@Icons.Material.Filled.Edit"
|
||||||
TooltipText="Edit"
|
TooltipText="Edit"
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
? context.Item.Teams.Where(t => t?.Event is { RegionalEvent: true }).OrderBy(t => t.Event.Name)
|
? context.Item.Teams.Where(t => t?.Event is { RegionalEvent: true }).OrderBy(t => t.Event.Name)
|
||||||
: context.Item.Teams.Where(t => t?.Event != null).OrderBy(t => t.Event.Name);
|
: context.Item.Teams.Where(t => t?.Event != null).OrderBy(t => t.Event.Name);
|
||||||
}
|
}
|
||||||
<div class="d-flex flex-wrap" style="gap: 0.25rem;">
|
<MudStack Row="true" Spacing="1" Wrap="Wrap.Wrap">
|
||||||
@foreach (var team in teamsToDisplay)
|
@foreach (var team in teamsToDisplay)
|
||||||
{
|
{
|
||||||
var isCaptain = team.Captain != null && team.Captain.Equals(context.Item.Student);
|
var isCaptain = team.Captain != null && team.Captain.Equals(context.Item.Student);
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
</MudChip>
|
</MudChip>
|
||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
}
|
}
|
||||||
</div>
|
</MudStack>
|
||||||
</CellTemplate>
|
</CellTemplate>
|
||||||
</TemplateColumn>
|
</TemplateColumn>
|
||||||
</Columns>
|
</Columns>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@using WebApp.Models
|
@using WebApp.Models
|
||||||
<div class="d-flex flex-wrap" style="gap: 0.25rem;">
|
<MudStack Row="true" Spacing="1" Wrap="Wrap.Wrap">
|
||||||
@foreach (var student in
|
@foreach (var student in
|
||||||
Team.Students
|
Team.Students
|
||||||
.OrderBy(e =>
|
.OrderBy(e =>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
</MudChip>
|
</MudChip>
|
||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
}
|
}
|
||||||
</div>
|
</MudStack>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter]
|
[Parameter]
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
{
|
{
|
||||||
<MudToggleItem Value="@team" Style="font-size: .75rem;">
|
<MudToggleItem Value="@team" Style="font-size: .75rem;">
|
||||||
<MudTooltip Text="@team.StudentsFirstNames">
|
<MudTooltip Text="@team.StudentsFirstNames">
|
||||||
<div class="d-flex align-center justify-space-between flex-wrap">
|
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="1" Wrap="Wrap.Wrap">
|
||||||
<MudText Class="ellipsis">@team.ToString()</MudText>
|
<MudText Class="ellipsis">@team.ToString()</MudText>
|
||||||
@if (ShowEventAttributes)
|
@if (ShowEventAttributes)
|
||||||
{
|
{
|
||||||
<EventAttributes EventDefinition="@team.Event"></EventAttributes>
|
<EventAttributes EventDefinition="@team.Event"></EventAttributes>
|
||||||
}
|
}
|
||||||
</div>
|
</MudStack>
|
||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
</MudToggleItem>
|
</MudToggleItem>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
@using WebApp.Models
|
@using WebApp.Models
|
||||||
@page "/teams"
|
@page "/teams"
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
|
@implements IAsyncDisposable
|
||||||
@inject AppDbContext Context
|
@inject AppDbContext Context
|
||||||
@inject IDialogService DialogService
|
@inject IDialogService DialogService
|
||||||
@inject ISnackbar Snackbar
|
@inject ISnackbar Snackbar
|
||||||
@@ -74,30 +75,58 @@
|
|||||||
MudDataGrid<Team> _dataGrid = null!;
|
MudDataGrid<Team> _dataGrid = null!;
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
private bool _showRegionalOnly = false;
|
private bool _showRegionalOnly = false;
|
||||||
|
private CancellationTokenSource? _cancellationTokenSource;
|
||||||
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
_cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ToggleRegionalFilter()
|
private async Task ToggleRegionalFilter()
|
||||||
{
|
{
|
||||||
|
if (_isDisposed) return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_showRegionalOnly = !_showRegionalOnly;
|
_showRegionalOnly = !_showRegionalOnly;
|
||||||
if (_dataGrid != null)
|
if (_dataGrid != null && !_isDisposed)
|
||||||
{
|
{
|
||||||
await _dataGrid.ReloadServerData();
|
await _dataGrid.ReloadServerData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Component was disposed, ignore
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
// JS connection lost, ignore
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
Snackbar.Add($"Error applying filter: {ex.Message}", Severity.Error);
|
Snackbar.Add($"Error applying filter: {ex.Message}", Severity.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<GridData<Team>> ServerReload(GridState<Team> state)
|
private async Task<GridData<Team>> ServerReload(GridState<Team> state)
|
||||||
{
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
return new GridData<Team> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
|
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
IQueryable<Team> query
|
IQueryable<Team> query
|
||||||
= Context.Teams
|
= Context.Teams
|
||||||
|
.AsNoTracking()
|
||||||
.Include(e => e.Event)
|
.Include(e => e.Event)
|
||||||
.Include(e => e.Students)
|
.Include(e => e.Students)
|
||||||
.ThenInclude(e => e.EventRankings);
|
.ThenInclude(e => e.EventRankings);
|
||||||
@@ -113,7 +142,7 @@
|
|||||||
query = query.Where(state.FilterDefinitions);
|
query = query.Where(state.FilterDefinitions);
|
||||||
|
|
||||||
// Load all data first
|
// Load all data first
|
||||||
var allTeams = await query.ToArrayAsync();
|
var allTeams = await query.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
// Always sort by EventFormat FIRST to separate group/individual teams
|
// Always sort by EventFormat FIRST to separate group/individual teams
|
||||||
// Sort in memory to ensure this ordering is maintained regardless of user sorts
|
// Sort in memory to ensure this ordering is maintained regardless of user sorts
|
||||||
@@ -173,15 +202,32 @@
|
|||||||
Items = pagedData
|
Items = pagedData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Component was disposed, return empty result
|
||||||
|
return new GridData<Team> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
// JS connection lost, return empty result
|
||||||
|
return new GridData<Team> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task DeleteTeam(Team team)
|
private async Task DeleteTeam(Team team)
|
||||||
{
|
{
|
||||||
//_isRowBlocked = true;
|
if (_isDisposed) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
var result = await DialogService
|
var result = await DialogService
|
||||||
.ShowMessageBox("Delete team",
|
.ShowMessageBox("Delete team",
|
||||||
@@ -189,6 +235,8 @@
|
|||||||
yesText: "Yes",
|
yesText: "Yes",
|
||||||
noText: "Cancel");
|
noText: "Cancel");
|
||||||
|
|
||||||
|
if (_isDisposed) return;
|
||||||
|
|
||||||
if (result == true)
|
if (result == true)
|
||||||
{
|
{
|
||||||
// If deleting a numbered team (1 or 2), clear the identifier of the remaining team
|
// If deleting a numbered team (1 or 2), clear the identifier of the remaining team
|
||||||
@@ -196,7 +244,9 @@
|
|||||||
{
|
{
|
||||||
var remainingTeam = await Context.Teams
|
var remainingTeam = await Context.Teams
|
||||||
.Include(t => t.Event)
|
.Include(t => t.Event)
|
||||||
.FirstOrDefaultAsync(t => t.Event.Id == team.Event.Id && t.Id != team.Id);
|
.FirstOrDefaultAsync(t => t.Event.Id == team.Event.Id && t.Id != team.Id, cancellationToken);
|
||||||
|
|
||||||
|
if (_isDisposed) return;
|
||||||
|
|
||||||
if (remainingTeam != null)
|
if (remainingTeam != null)
|
||||||
{
|
{
|
||||||
@@ -206,12 +256,46 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
Context.Teams.Remove(team!);
|
Context.Teams.Remove(team!);
|
||||||
await Context.SaveChangesAsync();
|
await Context.SaveChangesAsync(cancellationToken);
|
||||||
Snackbar.Add($"Delete event: Delete of Team {team}", Severity.Info);
|
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Team {team} deleted", Severity.Info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//_isRowBlocked = false;
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
await _dataGrid.ReloadServerData();
|
await _dataGrid.ReloadServerData();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Component was disposed, ignore
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
// JS connection lost, ignore
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error deleting team: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
_isDisposed = true;
|
||||||
|
_cancellationTokenSource?.Cancel();
|
||||||
|
_cancellationTokenSource?.Dispose();
|
||||||
|
_cancellationTokenSource = null;
|
||||||
|
}
|
||||||
|
await ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user