@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 Create New Printable Descriptions Career Mapping @context.Item.Name [@context.Item.MinTeamSize - @context.Item.MaxTeamSize] @code { MudDataGrid _dataGrid = null!; private bool _isLoading = true; private CancellationTokenSource? _cancellationTokenSource; private bool _isDisposed = false; protected override void OnInitialized() { _cancellationTokenSource = new CancellationTokenSource(); } private async Task> ServerReload(GridState state) { if (_isDisposed) { return new GridData { 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 { TotalItems = totalItems, Items = pagedData }; } catch (TaskCanceledException) { return new GridData { TotalItems = 0, Items = [] }; } catch (JSDisconnectedException) { return new GridData { 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 {evt.Name}? 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; } }