@namespace WebApp.Components.Features.Teams @using Core.Entities @using WebApp.Services @using Microsoft.AspNetCore.Components @using WebApp.Models @using WebApp.Components.Shared.Components @using Core.Utility @inject ITeamMeetingHistoryService TeamMeetingHistoryService @implements IAsyncDisposable @TeamName Meeting History @if (_isLoading) { } else if (!_meetingHistories.Any()) { No meeting history found for this team. } else { Date Team Members @{ var team = context.Teams.FirstOrDefault(t => t.Id == TeamId); var presentStudentIds = context.Students.Select(s => s.Id).ToHashSet(); var absentStudents = team?.Students.Where(s => !presentStudentIds.Contains(s.Id)).ToList() ?? []; } @context.MeetingDate.ToString("MM/dd/yyyy") @if (team != null) { @foreach (var student in team.Students) { var isAbsent = absentStudents.Contains(student); var formattedName = TeamStudentNameFormatter.FormatStudentName( student, team, new TeamStudentNameFormatter.FormatOptions { MarkAbsent = true, AbsentStudents = absentStudents }); @formattedName } } } Close @code { [CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!; [Parameter] public int TeamId { get; set; } [Parameter] public string TeamName { get; set; } = string.Empty; private List _meetingHistories = []; private bool _isLoading = true; private CancellationTokenSource? _cancellationTokenSource; private bool _isDisposed = false; protected override void OnInitialized() { _cancellationTokenSource = new CancellationTokenSource(); } protected override async Task OnInitializedAsync() { await LoadMeetingHistories(); } private async Task LoadMeetingHistories() { if (_isDisposed) return; try { var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None; var histories = await TeamMeetingHistoryService.GetMeetingHistoriesForTeamAsync(TeamId); _meetingHistories = histories.ToList(); } catch (TaskCanceledException) { // Component was disposed, ignore } catch (JSDisconnectedException) { // JS connection lost, ignore } catch (Exception ex) { if (!_isDisposed) { System.Diagnostics.Debug.WriteLine($"Error loading meeting histories: {ex.Message}"); } } finally { if (!_isDisposed) { _isLoading = false; StateHasChanged(); } } } private void Close() { if (_isDisposed) return; MudDialog.Close(); } public async ValueTask DisposeAsync() { if (!_isDisposed) { _isDisposed = true; _cancellationTokenSource?.Cancel(); _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; } await ValueTask.CompletedTask; } }