Files
chapter-organizer/WebApp/Components/Features/Calendar/Index.razor
T

265 lines
9.4 KiB
Plaintext

@page "/calendar"
@attribute [Authorize]
@using WebApp.Models
@using WebApp.Services
@using Heron.MudCalendar
@using Microsoft.Extensions.Logging
@using WebApp.Authentication
@using Core.Utility
@inject IEventOccurrenceService EventOccurrenceService
@inject ILogger<Index> Logger
@inject IDialogService DialogService
<PageHeader Title="Event Calendar" Description="View competition schedules and event occurrences" Icon="@AppIcons.EventCalendar">
<ActionButtons>
<MudButton StartIcon="@Icons.Material.Filled.ImportExport" Href="calendar/event-occurrences/import" Variant="Variant.Filled" Color="Color.Primary">Import</MudButton>
<AuthorizeView Roles="@AuthRoles.Administrator">
<MudButton StartIcon="@Icons.Material.Filled.AdminPanelSettings" Href="calendar/admin" Variant="Variant.Outlined" Color="Color.Default">Admin</MudButton>
</AuthorizeView>
<PageNoteButton PageIdentifier="Event Calendar" />
</ActionButtons>
</PageHeader>
<MudPaper Elevation="2" Class="pa-3 pa-md-6">
@if (_calendarItems == null)
{
<MudProgressLinear Indeterminate="true" />
<MudText>Loading calendar events...</MudText>
}
else
{
<MudStack Spacing="2">
<MudButtonGroup Variant="Variant.Outlined" Size="Size.Small">
<MudButton Color="@(_currentView == CalendarView.Month ? Color.Primary : Color.Default)"
OnClick="() => { _currentView = CalendarView.Month; StateHasChanged(); }">
Month
</MudButton>
<MudButton Color="@(_currentView == CalendarView.Day ? Color.Primary : Color.Default)"
OnClick="() => { _currentView = CalendarView.Day; StateHasChanged(); }">
Day
</MudButton>
</MudButtonGroup>
<MudCalendar T="CalendarEventItem"
Items="_calendarItems"
View="_currentView"
CurrentDay="@_calendarDate"
Class="event-calendar"
ItemClicked="OnItemClicked">
<MonthTemplate>
@* <MudTooltip Text="@GetEventTooltip(context)"> *@
<div class="d-flex gap-1">
<MudIcon Icon="@Icons.Material.Filled.Circle" Color="Color.Secondary" Size="Size.Small"/>
<div>@context.Text</div>
</div>
@* </MudTooltip> *@
</MonthTemplate>
<WeekTemplate>
@* <MudTooltip Text="@GetEventTooltip(context)"> *@
<div style="width: 100%; height: 100%;">
@context.Text
</div>
@* </MudTooltip> *@
</WeekTemplate>
<DayTemplate>
@* <MudTooltip Text="@GetEventTooltip(context)"> *@
<div>@context.Text</div>
@* </MudTooltip> *@
</DayTemplate>
</MudCalendar>
</MudStack>
}
</MudPaper>
@code {
private List<CalendarEventItem>? _calendarItems;
private DateTime _calendarDate = DateTime.Today;
private CalendarView _currentView = CalendarView.Month;
protected override async Task OnInitializedAsync()
{
await LoadCalendarEvents();
}
private async Task LoadCalendarEvents()
{
try
{
Logger.LogInformation("Loading calendar events");
var occurrences = await EventOccurrenceService.GetEventOccurrencesAsync();
var eventOccurrences = occurrences as EventOccurrence[] ?? occurrences.ToArray();
Logger.LogDebug("Received {Count} occurrences from service", eventOccurrences.Count());
// Get all unique event definition IDs that have occurrences
var eventDefinitionIds = eventOccurrences
.Where(occ => occ?.EventDefinition?.Id != null)
.Select(occ => occ!.EventDefinition!.Id)
.Distinct()
.ToList();
// Load teams for all event definitions
var teamsByEventId = await EventOccurrenceService.GetTeamsByEventDefinitionIdsAsync(eventDefinitionIds);
List<CalendarEventItem> items = [];
foreach (var occ in eventOccurrences)
{
try
{
if (string.IsNullOrEmpty(occ.Name))
{
Logger.LogWarning("Occurrence with Id={Id} has null or empty Name", occ.Id);
}
// Get student first names for this event definition
var studentFirstNames = occ.EventDefinition != null && teamsByEventId.TryGetValue(occ.EventDefinition.Id, out var teams)
? TeamStudentNameFormatter.FormatStudentListForEvent(
occ.EventDefinition,
teams,
new TeamStudentNameFormatter.FormatOptions
{
CaptainIndicator = TeamStudentNameFormatter.CaptainIndicatorStyle.Star,
Ordering = TeamStudentNameFormatter.OrderingStyle.Alphabetical
})
: [];
var calendarItem = new CalendarEventItem(occ, studentFirstNames);
items.Add(calendarItem);
}
catch (Exception ex)
{
Logger.LogError(ex, "Error creating CalendarEventItem for occurrence Id={Id}, Name={Name}",
occ?.Id, occ?.Name);
// Continue processing other items
}
}
_calendarItems = items;
Logger.LogInformation("Created {Count} calendar items from {OccurrenceCount} occurrences",
_calendarItems.Count, eventOccurrences.Count());
// Find the next date with events
_calendarDate = GetNextDateWithEvents();
}
catch (Exception ex)
{
Logger.LogError(ex, "Error loading calendar events");
_calendarItems = [];
}
finally
{
StateHasChanged();
}
}
private DateTime GetNextDateWithEvents()
{
try
{
if (_calendarItems == null || !_calendarItems.Any())
{
Logger.LogDebug("No calendar items available, returning today's date");
return DateTime.Today;
}
var today = DateTime.Today;
var nextEvent = _calendarItems
.Where(item =>
{
try
{
return item.Start.Date >= today;
}
catch (Exception ex)
{
Logger.LogWarning(ex, "Error checking item date, skipping item");
return false;
}
})
.OrderBy(item => item.Start)
.FirstOrDefault();
if (nextEvent != null)
{
return nextEvent.Start.Date;
}
// Fallback to first event if no future events
var firstEvent = _calendarItems
.OrderBy(item => item.Start)
.FirstOrDefault();
return firstEvent != null ? firstEvent.Start.Date : DateTime.Today;
}
catch (Exception ex)
{
Logger.LogError(ex, "Error in GetNextDateWithEvents");
return DateTime.Today;
}
}
private string GetEventTooltip(CalendarEventItem item)
{
List<string> parts = [];
if (!string.IsNullOrEmpty(item.EventDefinition?.Name))
{
parts.Add($"Event: {item.EventDefinition.Name}");
}
if (!string.IsNullOrEmpty(item.EventOccurrenceData?.Name))
{
parts.Add($"Occurrence: {item.EventOccurrenceData.Name}");
}
if (!string.IsNullOrEmpty(item.EventOccurrenceData?.Location))
{
parts.Add($"Location: {item.EventOccurrenceData.Location}");
}
if (item.EventOccurrenceData?.StartTime != null)
{
parts.Add($"Time: {item.EventOccurrenceData.StartTime:g}");
}
if (item.StudentFirstNames.Any())
{
parts.Add($"Students: {string.Join(", ", item.StudentFirstNames)}");
}
return string.Join("\n", parts);
}
private async Task OnItemClicked(CalendarEventItem calendarEventItem)
{
if (_calendarItems == null)
return;
await ShowEventDetails(calendarEventItem);
}
private async Task ShowEventDetails(CalendarEventItem item)
{
if (item.EventOccurrenceData == null) return;
var parameters = new DialogParameters
{
["EventOccurrence"] = item.EventOccurrenceData,
["EventDefinition"] = item.EventDefinition,
["StudentFirstNames"] = item.StudentFirstNames
};
var options = new DialogOptions
{
CloseOnEscapeKey = true,
CloseButton = true,
MaxWidth = MaxWidth.Medium,
FullWidth = true
};
await DialogService.ShowAsync<EventOccurrenceDetailsDialog>("Event Details", parameters, options);
}
}