@namespace WebApp.Components.Features.MeetingSchedule @using Core.Entities @using Core.Services @using Core.Utility @using WebApp.Services @using WebApp.Components.Shared.Components @using WebApp.Models @inject ITeamMeetingHistoryService TeamMeetingHistoryService @inject INotesService NotesService @inject INoteNamingService NoteNamingService @inject ISnackbar Snackbar @inject IDialogService DialogService @implements IAsyncDisposable @if (_isLoading) { } else if (_meetingHistory == null) { Meeting history not found. } else { Meeting Details Date: @_meetingHistory.MeetingDate.ToString("MM/dd/yyyy") Teams That Met (@_meetingHistory.Teams.Count) @foreach (var team in _meetingHistory.Teams.OrderByEventFormatFirst().ThenBy(e => e.ToString())) { @team.ToString() } Students (@GetAllStudentsFromTeams().Count) @{ var presentStudentIds = _meetingHistory.Students.Select(s => s.Id).ToHashSet(); var allStudents = GetAllStudentsFromTeams().OrderBy(s => s.FirstName); } @foreach (var student in allStudents) { var isPresent = presentStudentIds.Contains(student.Id); @student.FirstNameLastName } @if (_meetingNote != null) { Meeting Notes @_meetingNote.Title @if (!string.IsNullOrWhiteSpace(_meetingNote.Content)) { @((MarkupString)MarkdownHelper.ToHtml(_meetingNote.Content)) } Edit Note } } @if (_meetingHistory != null) { Delete Close } else { Close } @code { [CascadingParameter] IMudDialogInstance MudDialog { get; set; } = null!; [Parameter] public int MeetingHistoryId { get; set; } private TeamMeetingHistory? _meetingHistory; private Note? _meetingNote; private bool _isLoading = true; private bool _isDeleting = false; private CancellationTokenSource? _cancellationTokenSource; private bool _isDisposed = false; private bool IsActionDisabled => _isLoading || _isDeleting; protected override void OnInitialized() { _cancellationTokenSource = new CancellationTokenSource(); } protected override async Task OnInitializedAsync() { await LoadMeetingHistory(); } private async Task LoadMeetingHistory() { if (_isDisposed) return; try { _meetingHistory = await TeamMeetingHistoryService.GetMeetingHistoryAsync(MeetingHistoryId); // Load note by title if meeting history exists if (_meetingHistory != null) { _meetingNote = await TeamMeetingHistoryService.GetMeetingNoteAsync(_meetingHistory.MeetingDate); } } catch (TaskCanceledException) { // Component was disposed, ignore } catch (JSDisconnectedException) { // JS connection lost, ignore } catch (Exception ex) { if (!_isDisposed) { Snackbar.Add($"Error loading meeting history: {ex.Message}", Severity.Error); } } finally { if (!_isDisposed) { _isLoading = false; StateHasChanged(); } } } private async Task ConfirmDelete() { if (_isDisposed || _isDeleting || _meetingHistory == null) return; var result = await DialogService.ShowMessageBox( "Confirm Delete", $"Are you sure you want to delete the meeting history for {_meetingHistory.MeetingDate:MM/dd/yyyy}? This action cannot be undone.", yesText: "Delete", cancelText: "Cancel"); if (result == true) { await DeleteMeetingHistory(); } } private async Task DeleteMeetingHistory() { if (_isDisposed || _isDeleting || _meetingHistory == null) return; try { _isDeleting = true; StateHasChanged(); await TeamMeetingHistoryService.DeleteMeetingHistoryAsync(MeetingHistoryId); if (!_isDisposed) { Snackbar.Add("Meeting history deleted successfully", Severity.Success); MudDialog.Close(DialogResult.Ok(true)); } } catch (TaskCanceledException) { // Component was disposed, ignore } catch (JSDisconnectedException) { // JS connection lost, ignore } catch (Exception ex) { if (!_isDisposed) { Snackbar.Add($"Error deleting meeting history: {ex.Message}", Severity.Error); _isDeleting = false; StateHasChanged(); } } } private async Task ViewNote() { if (_meetingNote == null) return; var parameters = new DialogParameters { ["NoteId"] = _meetingNote.Id }; var options = new DialogOptions { MaxWidth = MaxWidth.Medium, FullWidth = true, CloseButton = true }; var dialog = await DialogService.ShowAsync("Meeting Notes", parameters, options); await dialog.Result; // Refresh meeting history to get updated note await LoadMeetingHistory(); } private List GetAllStudentsFromTeams() { if (_meetingHistory == null) return []; var allStudents = new List(); var studentIds = new HashSet(); foreach (var team in _meetingHistory.Teams) { foreach (var student in team.Students) { if (!studentIds.Contains(student.Id)) { studentIds.Add(student.Id); allStudents.Add(student); } } } return allStudents; } 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; } }