265 lines
9.4 KiB
Plaintext
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);
|
|
}
|
|
}
|
|
|