aba8ea3ae3
This commit updates the deletion logic in the Index.razor components for Events, Students, and Teams to load the entities fresh from the database with tracking. This change prevents tracking conflicts and ensures that the correct entity is deleted. Additionally, it adds error handling to notify users if the entity is not found or has already been deleted, enhancing the user experience and reliability of the deletion process.
205 lines
7.4 KiB
Plaintext
205 lines
7.4 KiB
Plaintext
@page "/events"
|
|
@attribute [Authorize]
|
|
@implements IAsyncDisposable
|
|
@using Microsoft.EntityFrameworkCore
|
|
@using WebApp.Models
|
|
@using WebApp.Components.Shared.Components
|
|
@inject AppDbContext Context
|
|
@inject IDialogService DialogService
|
|
@inject ISnackbar Snackbar
|
|
|
|
<PageHeader Title="Events">
|
|
<ActionButtons>
|
|
<MudButton StartIcon="@Icons.Material.Filled.Create" Href="events/create" Variant="Variant.Filled" Color="Color.Primary">Create New</MudButton>
|
|
<MudButton StartIcon="@Icons.Material.Filled.Print" Href="events/printout" Variant="Variant.Outlined">Printable Descriptions</MudButton>
|
|
<MudButton StartIcon="@Icons.Material.Filled.AccountTree" Href="events/career-mapping" Variant="Variant.Outlined">Career Mapping</MudButton>
|
|
</ActionButtons>
|
|
</PageHeader>
|
|
|
|
<MudPaper Elevation="2" Class="pa-3 pa-md-6">
|
|
<MudDataGrid T="EventDefinition"
|
|
ServerData="ServerReload"
|
|
@ref="_dataGrid"
|
|
Filterable="true"
|
|
RowsPerPage="50"
|
|
Dense="true"
|
|
Striped="true"
|
|
Hover="true"
|
|
Loading="@_isLoading"
|
|
LoadingProgressColor="Color.Primary">
|
|
<Columns>
|
|
<PropertyColumn Property="@(e => e.Name)" Title="Event Name" Sortable="true">
|
|
<CellTemplate>
|
|
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Spacing="1">
|
|
<MudLink Href="@($"/events/details?id={context.Item.Id}&returnUrl=/events")"
|
|
Underline="Underline.Hover"
|
|
Color="Color.Primary">
|
|
@context.Item.Name
|
|
</MudLink>
|
|
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
|
<IconButtonWithTooltip Icon="@Icons.Material.Filled.Edit"
|
|
TooltipText="Edit"
|
|
Href="@($"/events/edit?id={context.Item.Id}&returnUrl=/events")" />
|
|
<IconButtonWithTooltip Icon="@Icons.Material.Outlined.Delete"
|
|
TooltipText="Delete"
|
|
HoverColor="Color.Error"
|
|
OnClick="() => DeleteEventDefinition(context.Item!)" />
|
|
</MudStack>
|
|
</MudStack>
|
|
</CellTemplate>
|
|
</PropertyColumn>
|
|
<TemplateColumn Title="Attributes" Sortable="false">
|
|
<CellTemplate>
|
|
<EventAttributes EventDefinition="context.Item"></EventAttributes>
|
|
</CellTemplate>
|
|
</TemplateColumn>
|
|
|
|
<TemplateColumn Title="Team Size" CellStyle="white-space:nowrap">
|
|
<CellTemplate>
|
|
<MudTooltip Text="@context.Item.Eligibility">
|
|
[@context.Item.MinTeamSize - @context.Item.MaxTeamSize]
|
|
</MudTooltip>
|
|
</CellTemplate>
|
|
</TemplateColumn>
|
|
|
|
<PropertyColumn Property="@(e => e.LevelOfEffort)" Title="Level of Effort" />
|
|
<PropertyColumn Property="@(e => e.EventFormat)" Title="Event Format" />
|
|
|
|
</Columns>
|
|
<PagerContent>
|
|
<MudDataGridPager T="EventDefinition"></MudDataGridPager>
|
|
</PagerContent>
|
|
</MudDataGrid>
|
|
</MudPaper>
|
|
|
|
@code {
|
|
MudDataGrid<EventDefinition> _dataGrid = null!;
|
|
private bool _isLoading = true;
|
|
private CancellationTokenSource? _cancellationTokenSource;
|
|
private bool _isDisposed = false;
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
}
|
|
|
|
private async Task<GridData<EventDefinition>> ServerReload(GridState<EventDefinition> state)
|
|
{
|
|
if (_isDisposed)
|
|
{
|
|
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
|
}
|
|
|
|
_isLoading = true;
|
|
try
|
|
{
|
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
|
|
|
var query = Context.Events
|
|
.AsNoTracking()
|
|
.OrderBy(e => e.Name).Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
|
|
|
var totalItems = await query.CountAsync(cancellationToken);
|
|
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync(cancellationToken);
|
|
|
|
return new GridData<EventDefinition>
|
|
{
|
|
TotalItems = totalItems,
|
|
Items = pagedData
|
|
};
|
|
}
|
|
catch (TaskCanceledException)
|
|
{
|
|
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
|
}
|
|
catch (JSDisconnectedException)
|
|
{
|
|
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
|
}
|
|
finally
|
|
{
|
|
if (!_isDisposed)
|
|
{
|
|
_isLoading = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task DeleteEventDefinition(EventDefinition evt)
|
|
{
|
|
if (_isDisposed) return;
|
|
|
|
try
|
|
{
|
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
|
|
|
var result = await DialogService
|
|
.ShowMessageBox("Delete Event",
|
|
(MarkupString)$"Are you sure want to delete <b>{evt.Name}</b>? This cannot be undone.",
|
|
yesText:"Yes",
|
|
noText:"Cancel");
|
|
|
|
if (_isDisposed) return;
|
|
|
|
if (result == true)
|
|
{
|
|
// Load the event fresh from database with tracking to avoid tracking conflicts
|
|
var eventToDelete = await Context.Events
|
|
.FirstOrDefaultAsync(e => e.Id == evt.Id, cancellationToken);
|
|
|
|
if (_isDisposed) return;
|
|
|
|
if (eventToDelete == null)
|
|
{
|
|
if (!_isDisposed)
|
|
{
|
|
Snackbar.Add("Event not found or already deleted", Severity.Warning);
|
|
}
|
|
return;
|
|
}
|
|
|
|
Context.Events.Remove(eventToDelete);
|
|
await Context.SaveChangesAsync(cancellationToken);
|
|
|
|
if (!_isDisposed)
|
|
{
|
|
Snackbar.Add($"Event {eventToDelete.Name} deleted", Severity.Info);
|
|
}
|
|
}
|
|
|
|
if (!_isDisposed)
|
|
{
|
|
StateHasChanged();
|
|
await _dataGrid.ReloadServerData();
|
|
}
|
|
}
|
|
catch (TaskCanceledException)
|
|
{
|
|
// Component was disposed, ignore
|
|
}
|
|
catch (JSDisconnectedException)
|
|
{
|
|
// JS connection lost, ignore
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (!_isDisposed)
|
|
{
|
|
Snackbar.Add($"Error deleting event: {ex.Message}", Severity.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
if (!_isDisposed)
|
|
{
|
|
_isDisposed = true;
|
|
_cancellationTokenSource?.Cancel();
|
|
_cancellationTokenSource?.Dispose();
|
|
_cancellationTokenSource = null;
|
|
}
|
|
await ValueTask.CompletedTask;
|
|
}
|
|
}
|