@page "/meeting-schedule/history"
@attribute [Authorize]
@using Core.Entities
@using Microsoft.EntityFrameworkCore
@using WebApp.Components.Shared.Components
@using WebApp.Services
@inject ITeamMeetingHistoryService TeamMeetingHistoryService
@inject AppDbContext Context
@inject IDialogService DialogService
@inject ISnackbar Snackbar
@inject IConfiguration Configuration
@implements IAsyncDisposable
Back to Schedule
@if (_isLoading)
{
}
else
{
@if (_meetingHistories.Any())
{
@foreach (var team in _allTeams)
{
}
Date
@{
var teamIndex = 0;
}
@foreach (var team in _allTeams)
{
var isEven = teamIndex % 2 == 0;
var bgColor = isEven ? "background-color: var(--mud-palette-background-grey);" : "";
var headerStyle = $"padding: 4px 2px; border-right: 1px solid var(--mud-palette-divider); {bgColor}";
@team.ToString()
teamIndex++;
}
@context.MeetingDate.ToString("MM/dd/yy")
@{
var rowTeamIndex = 0;
}
@foreach (var team in _allTeams)
{
var met = TeamMetOnDate(context, team);
var isEven = rowTeamIndex % 2 == 0;
var bgColor = isEven ? "background-color: var(--mud-palette-background-grey);" : "";
var cellStyle = $"padding: 4px 2px; border-right: 1px solid var(--mud-palette-divider); {bgColor}";
@if (met)
{
×
}
rowTeamIndex++;
}
Times Met
@{
var footerTeamIndex = 0;
}
@foreach (var team in _allTeams)
{
var timesMet = GetTimesMetForTeam(team);
var isEven = footerTeamIndex % 2 == 0;
var bgColor = isEven ? "background-color: var(--mud-palette-background-grey);" : "";
var footerCellStyle = $"padding: 4px 2px; border-right: 1px solid var(--mud-palette-divider); {bgColor}";
@timesMet
footerTeamIndex++;
}
}
else
{
No meeting history found. Save a meeting schedule to get started.
}
}
@code {
private List _meetingHistories = [];
private List _allTeams = [];
private Dictionary _timesMetDict = new();
private bool _isLoading = true;
private CancellationTokenSource? _cancellationTokenSource;
private bool _isDisposed = false;
protected override void OnInitialized()
{
_cancellationTokenSource = new CancellationTokenSource();
}
protected override async Task OnInitializedAsync()
{
await LoadData();
}
private async Task LoadData()
{
if (_isDisposed) return;
try
{
_isLoading = true;
StateHasChanged();
// Load all teams for columns
_allTeams = await Context.Teams
.AsNoTracking()
.Include(t => t.Event)
.OrderBy(t => t.Event.Name)
.ThenBy(t => t.Identifier)
.ToListAsync();
// Load meeting histories
await RefreshMeetingHistories();
// Calculate times met
CalculateTimesMet();
}
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 RefreshMeetingHistories()
{
_meetingHistories = (await TeamMeetingHistoryService.GetMeetingHistoriesAsync()).ToList();
// Extract all unique teams from meeting histories and merge with all teams
var teamsInHistory = _meetingHistories
.SelectMany(mh => mh.Teams)
.DistinctBy(t => t.Id)
.ToList();
// Merge with all teams, ensuring all teams are included
var allTeamIds = _allTeams.Select(t => t.Id).ToHashSet();
var newTeams = teamsInHistory.Where(t => !allTeamIds.Contains(t.Id)).ToList();
_allTeams = _allTeams.Concat(newTeams).OrderBy(t => t.Event?.Name ?? "").ThenBy(t => t.Identifier).ToList();
}
private void CalculateTimesMet()
{
_timesMetDict.Clear();
foreach (var team in _allTeams)
{
_timesMetDict[team.Id] = 0;
}
foreach (var history in _meetingHistories)
{
var teamIds = history.Teams.Select(t => t.Id).ToHashSet();
foreach (var teamId in teamIds)
{
if (_timesMetDict.ContainsKey(teamId))
{
_timesMetDict[teamId]++;
}
}
}
}
private int GetTimesMetForTeam(Team team)
{
return _timesMetDict.GetValueOrDefault(team.Id, 0);
}
private bool TeamMetOnDate(TeamMeetingHistory history, Team team)
{
return history.Teams.Any(t => t.Id == team.Id);
}
private async Task ViewMeetingDetails(TeamMeetingHistory history)
{
var parameters = new DialogParameters
{
["MeetingHistoryId"] = history.Id
};
var options = new DialogOptions
{
MaxWidth = MaxWidth.Large,
FullWidth = true,
CloseButton = true
};
var dialog = await DialogService.ShowAsync("Meeting Details", parameters, options);
var result = await dialog.Result;
if (!result.Canceled)
{
// Refresh data if meeting was updated or deleted
await RefreshMeetingHistories();
CalculateTimesMet();
if (!_isDisposed)
{
StateHasChanged();
}
}
}
public async ValueTask DisposeAsync()
{
if (!_isDisposed)
{
_isDisposed = true;
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
}
await ValueTask.CompletedTask;
}
}