@page "/" @attribute [Authorize] @using Microsoft.EntityFrameworkCore @using WebApp.Models @using Core.Entities @using WebApp.Services @using WebApp.Components.Shared.Components @using Heron.MudCalendar @inject IConfiguration Configuration @inject AppDbContext Context @inject INotesService NotesService @inject IDialogService DialogService @inject ITeamMeetingHistoryService TeamMeetingHistoryService @inject ICalendarService CalendarService @inject NavigationManager Navigation @implements IAsyncDisposable @Configuration["ChapterSettings:Name"] - TSA Chapter Organizer
@Configuration["ChapterSettings:Name"] @Configuration["ChapterSettings:Name"] @Configuration["ChapterSettings:CompetitionYear"] Competition Year
@if (_pinnedNotes.Any()) { @foreach (var note in _pinnedNotes) { } } @if (!_hasStudents) { Getting Started Add your chapter's students to begin Import or add your chapter roster } else if (!_hasTeams) { Team Building Collect event rankings and build your teams Chapter Data @if (!string.IsNullOrEmpty(_gradeDistribution) && _gradeDistribution != "No students yet") { @((MarkupString)_gradeDistribution) } } else { Scheduling @if (_recentMeetings.Any()) { Recent Meetings @foreach (var meeting in _recentMeetings) {
@meeting.MeetingDate.ToString("MMM d, yyyy")
}
View History
} else { Optimize meeting times }
@if (_nextCalendarItems.Any()) { Next Events @foreach (var item in _nextCalendarItems) { var itemDate = item.Start.Date; var itemName = item.ItemType == CalendarItemType.Event && item.EventItem != null ? (item.EventItem.EventDefinition?.ShortName ?? item.EventItem.EventOccurrenceData?.Name ?? "Event") : "Team Meeting"; var dateStr = itemDate.ToString("yyyy-MM-dd");
@itemName - @itemDate.ToString("MMM d, yyyy")
}
} else { Conference schedules }
Teams & Registration Chapter Data @if (!string.IsNullOrEmpty(_gradeDistribution) && _gradeDistribution != "No students yet") { @((MarkupString)_gradeDistribution) } Team Building } @code { private int _eventCount; private int _individualEventsCount; private int _teamEventsCount; private int _studentCount; private string _gradeDistribution = ""; private int _teamCount; private int _individualTeamsCount; private int _groupTeamsCount; private int _meetingHistoryCount; private List _recentMeetings = []; private List _nextCalendarItems = []; private List _pinnedNotes = []; private CancellationTokenSource? _cancellationTokenSource; private bool _isDisposed = false; private bool _hasStudents => _studentCount > 0; private bool _hasTeams => _teamCount > 0; protected override void OnInitialized() { _cancellationTokenSource = new CancellationTokenSource(); } protected override async Task OnInitializedAsync() { await LoadStatistics(); await LoadPinnedNotes(); await LoadMeetingHistoryCount(); await LoadNextCalendarItem(); } private async Task HandleNoteChanged() { if (!_isDisposed) { await LoadPinnedNotes(); StateHasChanged(); } } private async Task LoadPinnedNotes() { if (_isDisposed) return; try { var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None; _pinnedNotes = (await NotesService.GetPinnedNotesAsync()).ToList(); } catch (TaskCanceledException) { // Component was disposed, ignore } catch (JSDisconnectedException) { // JS connection lost, ignore } catch (Exception) { // Error loading pinned notes - ignore } } private async Task LoadStatistics() { // Events statistics var events = await Context.Events.ToListAsync(); _eventCount = events.Count(); _individualEventsCount = events.Count(e => e.EventFormat == EventFormat.Individual); _teamEventsCount = events.Count(e => e.EventFormat == EventFormat.Team); // Students statistics _studentCount = await Context.Students.CountAsync(); // Grade distribution var gradeGroups = await Context.Students .GroupBy(s => s.Grade) .Select(g => new { Grade = g.Key, Count = g.Count() }) .OrderBy(g => g.Grade) .ToListAsync(); if (gradeGroups.Any()) { _gradeDistribution = string.Join(" | ", gradeGroups.Select(g => $"{AppIcons.GetOrdinalSuperscript(g.Grade)}: {g.Count}")); } else { _gradeDistribution = "No students yet"; } // Teams statistics var contextTeams = await Context.Teams.ToListAsync(); _teamCount = contextTeams.Count; _individualTeamsCount = contextTeams.Count(e => e.Event.EventFormat == EventFormat.Individual); _groupTeamsCount = contextTeams.Count(e => e.Event.EventFormat == EventFormat.Team); } private async Task LoadMeetingHistoryCount() { if (_isDisposed) return; try { var meetingHistories = await TeamMeetingHistoryService.GetMeetingHistoriesAsync(); var historiesList = meetingHistories.ToList(); _meetingHistoryCount = historiesList.Count; // Get the 3 most recent meetings in descending order _recentMeetings = historiesList .OrderByDescending(m => m.MeetingDate) .ThenByDescending(m => m.Id) .Take(3) .ToList(); } catch (TaskCanceledException) { // Component was disposed, ignore } catch (JSDisconnectedException) { // JS connection lost, ignore } catch (Exception) { // Error loading meeting history - ignore _meetingHistoryCount = 0; _recentMeetings = []; } } private async Task ShowMeetingDetails(TeamMeetingHistory meeting) { var parameters = new DialogParameters { ["MeetingHistoryId"] = meeting.Id }; var options = new DialogOptions { CloseOnEscapeKey = true, CloseButton = true, MaxWidth = MaxWidth.Large, FullWidth = true }; await DialogService.ShowAsync("Meeting Details", parameters, options); } private async Task LoadNextCalendarItem() { if (_isDisposed) return; try { _nextCalendarItems = await CalendarService.GetUpcomingCalendarItemsAsync(3); } catch (TaskCanceledException) { // Component was disposed, ignore } catch (JSDisconnectedException) { // JS connection lost, ignore } catch (Exception) { // Error loading calendar items - ignore _nextCalendarItems = []; } } private void NavigateToCalendar(string date) { Navigation.NavigateTo($"/calendar?date={date}"); } public async ValueTask DisposeAsync() { if (!_isDisposed) { _isDisposed = true; _cancellationTokenSource?.Cancel(); _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; } await ValueTask.CompletedTask; } }