@namespace WebApp.Components.Features.MeetingSchedule
@using Core.Entities
@using Core.Calculation
@using Core.Services
@using WebApp.Services
@using WebApp.Components.Shared.Components
@using WebApp.Models
@inject ITeamMeetingHistoryService TeamMeetingHistoryService
@inject INotesService NotesService
@inject INoteNamingService NoteNamingService
@inject ISnackbar Snackbar
@implements IAsyncDisposable
@if (_isLoading)
{
}
else
{
Save Meeting History
Teams That Met
@foreach (var team in AllTeams.OrderByEventFormatFirst().ThenBy(e => e.ToString()))
{
@team.ToString()
}
Students Present
@foreach (var student in AllStudents.OrderBy(s => s.FirstName))
{
@student.FirstNameLastName
}
}
Cancel
@if (_isSaving)
{
Saving...
}
else
{
Save
}
@code {
[CascadingParameter]
IMudDialogInstance MudDialog { get; set; } = null!;
[Parameter]
public IEnumerable ScheduledTeams { get; set; } = [];
[Parameter]
public IEnumerable AbsentStudents { get; set; } = [];
[Parameter]
public IEnumerable AllTeams { get; set; } = [];
[Parameter]
public IEnumerable AllStudents { get; set; } = [];
private DateTime? _meetingDate = DateTime.Today;
private List _selectedTeams = [];
private List _selectedStudents = [];
private string _noteTitle = "";
private string _noteContent = "";
private bool _isLoading = true;
private bool _isSaving = false;
private CancellationTokenSource? _cancellationTokenSource;
private bool _isDisposed = false;
protected override void OnInitialized()
{
_cancellationTokenSource = new CancellationTokenSource();
}
protected override async Task OnInitializedAsync()
{
await LoadInitialData();
}
private async Task LoadInitialData()
{
if (_isDisposed) return;
try
{
// Initialize selected teams from scheduled teams
_selectedTeams = ScheduledTeams.ToList();
// Initialize selected students (all students except absent ones)
var absentStudentIds = AbsentStudents.Select(s => s.Id).ToHashSet();
_selectedStudents = AllStudents.Where(s => !absentStudentIds.Contains(s.Id)).ToList();
// Generate default note title if meeting date is set
if (_meetingDate.HasValue)
{
_noteTitle = NoteNamingService.GetMeetingNoteTitle(_meetingDate.Value);
}
}
catch (TaskCanceledException)
{
// Component was disposed, ignore
}
catch (JSDisconnectedException)
{
// JS connection lost, ignore
}
catch (Exception ex)
{
if (!_isDisposed)
{
Snackbar.Add($"Error loading data: {ex.Message}", Severity.Error);
}
}
finally
{
if (!_isDisposed)
{
_isLoading = false;
StateHasChanged();
}
}
}
private bool IsSaveDisabled => _isSaving || _isLoading;
protected override async Task OnParametersSetAsync()
{
if (_meetingDate.HasValue && string.IsNullOrEmpty(_noteTitle))
{
_noteTitle = NoteNamingService.GetMeetingNoteTitle(_meetingDate.Value);
}
await base.OnParametersSetAsync();
}
private async Task OnMeetingDateChanged(DateTime? date)
{
_meetingDate = date;
if (date.HasValue)
{
_noteTitle = NoteNamingService.GetMeetingNoteTitle(date.Value);
}
await InvokeAsync(StateHasChanged);
}
private void OnTeamsChanged(IEnumerable teams)
{
_selectedTeams = teams.ToList();
StateHasChanged();
}
private void OnStudentsChanged(IEnumerable students)
{
_selectedStudents = students.ToList();
StateHasChanged();
}
private async Task Save()
{
if (_isDisposed || _isSaving) return;
if (!_meetingDate.HasValue)
{
Snackbar.Add("Please select a meeting date", Severity.Warning);
return;
}
try
{
_isSaving = true;
StateHasChanged();
// Create or update note if note content is provided
Note? note = null;
if (!string.IsNullOrWhiteSpace(_noteContent))
{
// Use the naming service to get the meeting note title
var noteTitle = NoteNamingService.GetMeetingNoteTitle(_meetingDate.Value);
// Check if note already exists
var existingNote = await NotesService.GetNotesAsync(includeDeleted: false);
note = existingNote.FirstOrDefault(n => n.Title == noteTitle);
if (note != null)
{
// Update existing note
note.Content = _noteContent;
note = await NotesService.UpdateNoteAsync(note);
}
else
{
// Create new note
note = new Note
{
Title = noteTitle,
Content = _noteContent
};
note = await NotesService.CreateNoteAsync(note);
}
}
// Create meeting history
var meetingHistory = new TeamMeetingHistory
{
MeetingDate = _meetingDate.Value,
Teams = _selectedTeams,
Students = _selectedStudents
};
await TeamMeetingHistoryService.CreateMeetingHistoryAsync(meetingHistory);
if (!_isDisposed)
{
Snackbar.Add($"Meeting history saved for {_meetingDate.Value:MM/dd/yyyy}", 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 saving meeting history: {ex.Message}", Severity.Error);
_isSaving = false;
StateHasChanged();
}
}
}
private void Cancel()
{
if (_isDisposed) return;
MudDialog.Cancel();
}
public async ValueTask DisposeAsync()
{
if (!_isDisposed)
{
_isDisposed = true;
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
}
await ValueTask.CompletedTask;
}
}