diff --git a/WebApp/Components/Features/EventCalendar/Index.razor b/WebApp/Components/Features/EventCalendar/Index.razor new file mode 100644 index 0000000..3fbc7e5 --- /dev/null +++ b/WebApp/Components/Features/EventCalendar/Index.razor @@ -0,0 +1,63 @@ +@page "/event-calendar" +@attribute [Authorize] +@using WebApp.Components.Shared.Components +@using WebApp.Models +@using WebApp.Services +@using Heron.MudCalendar +@inject IEventOccurrenceService EventOccurrenceService + + + + + @if (_calendarItems == null) + { + + Loading calendar events... + } + else + { + + } + + +@code { + private List? _calendarItems; + private DateTime _calendarDate = DateTime.Today; + + protected override async Task OnInitializedAsync() + { + await LoadCalendarEvents(); + } + + private async Task LoadCalendarEvents() + { + var occurrences = await EventOccurrenceService.GetEventOccurrencesAsync(); + _calendarItems = occurrences + .Select(occ => new CalendarEventItem(occ)) + .ToList(); + + // Find the next date with events + _calendarDate = GetNextDateWithEvents(); + } + + private DateTime GetNextDateWithEvents() + { + if (_calendarItems == null || !_calendarItems.Any()) + { + return DateTime.Today; + } + + var today = DateTime.Today; + var nextEvent = _calendarItems + .Where(item => item.Start.Date >= today) + .OrderBy(item => item.Start) + .FirstOrDefault(); + + return nextEvent?.Start.Date ?? _calendarItems.OrderBy(item => item.Start).First().Start.Date; + } +} + diff --git a/WebApp/Components/Shared/Layout/NavMenu.razor b/WebApp/Components/Shared/Layout/NavMenu.razor index 5b4df0a..c4451b2 100644 --- a/WebApp/Components/Shared/Layout/NavMenu.razor +++ b/WebApp/Components/Shared/Layout/NavMenu.razor @@ -17,6 +17,7 @@ Handout Schedule + Event Calendar Event Ranking Team Assignment diff --git a/WebApp/Components/_Imports.razor b/WebApp/Components/_Imports.razor index dae51f2..241d5f5 100644 --- a/WebApp/Components/_Imports.razor +++ b/WebApp/Components/_Imports.razor @@ -22,6 +22,7 @@ @using WebApp.Components.Features.Events @using WebApp.Components.Features.Events.Components @using WebApp.Components.Features.MeetingSchedule +@using WebApp.Components.Features.EventCalendar @using MudBlazor @using Core.Entities @using Data diff --git a/WebApp/Models/CalendarEventItem.cs b/WebApp/Models/CalendarEventItem.cs new file mode 100644 index 0000000..f7a0aaf --- /dev/null +++ b/WebApp/Models/CalendarEventItem.cs @@ -0,0 +1,55 @@ +using Heron.MudCalendar; +using MudBlazor; + +namespace WebApp.Models; + +/// +/// Calendar event item model for Heron.MudCalendar component. +/// Maps from EventOccurrence entity to calendar event format. +/// +public class CalendarEventItem : CalendarItem +{ + /// + /// Gets the original EventOccurrence data. + /// + public Core.Entities.EventOccurrence? EventOccurrenceData { get; set; } + + /// + /// Gets the associated EventDefinition if available. + /// + public Core.Entities.EventDefinition? EventDefinition { get; set; } + + /// + /// Parameterless constructor required by Heron.MudCalendar component. + /// + public CalendarEventItem() + { + } + + public CalendarEventItem(Core.Entities.EventOccurrence occurrence, Core.Entities.EventDefinition? eventDefinition = null) + { + // Set base class properties that the calendar component uses + Text = GetEventTitle(occurrence, eventDefinition); + Start = occurrence.StartTime; + End = occurrence.EndTime ?? occurrence.StartTime.AddHours(1); + this.EventOccurrenceData = occurrence; + this.EventDefinition = eventDefinition; + } + + private static string GetEventTitle(Core.Entities.EventOccurrence occurrence, Core.Entities.EventDefinition? eventDefinition) + { + var title = occurrence.Name; + + if (eventDefinition != null && !string.IsNullOrEmpty(eventDefinition.Name)) + { + title = $"{eventDefinition.Name} - {title}"; + } + + if (!string.IsNullOrEmpty(occurrence.Location)) + { + title += $" ({occurrence.Location})"; + } + + return title; + } +} diff --git a/WebApp/Program.cs b/WebApp/Program.cs index 941ad4d..4e10945 100644 --- a/WebApp/Program.cs +++ b/WebApp/Program.cs @@ -172,6 +172,7 @@ builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); // State container for maintaining state per user connection (Blazor Server) builder.Services.AddScoped(); diff --git a/WebApp/Services/EventOccurrenceService.cs b/WebApp/Services/EventOccurrenceService.cs new file mode 100644 index 0000000..16d3c6f --- /dev/null +++ b/WebApp/Services/EventOccurrenceService.cs @@ -0,0 +1,92 @@ +using Core.Entities; + +namespace WebApp.Services; + +public class EventOccurrenceService : IEventOccurrenceService +{ + public Task> GetEventOccurrencesAsync() + { + // Mock data for demonstration purposes + // This will be replaced with database-backed implementation later + var mockOccurrences = new List + { + new EventOccurrence + { + Name = "Opening Ceremony", + Date = "March 15", + Time = "8:00 a.m.", + StartTime = new DateTime(2026, 3, 15, 8, 0, 0), + EndTime = new DateTime(2026, 3, 15, 9, 0, 0), + Location = "Main Auditorium" + }, + new EventOccurrence + { + Name = "Sign-up", + Date = "March 15", + Time = "9:30 a.m.", + StartTime = new DateTime(2026, 3, 15, 9, 30, 0), + EndTime = new DateTime(2026, 3, 15, 11, 0, 0), + Location = "Registration Hall" + }, + new EventOccurrence + { + Name = "Judging", + Date = "March 15", + Time = "1:00 p.m.", + StartTime = new DateTime(2026, 3, 15, 13, 0, 0), + EndTime = new DateTime(2026, 3, 15, 17, 0, 0), + Location = "Exhibition Hall" + }, + new EventOccurrence + { + Name = "Submit", + Date = "March 16", + Time = "8:00 a.m.", + StartTime = new DateTime(2026, 3, 16, 8, 0, 0), + EndTime = new DateTime(2026, 3, 16, 10, 0, 0), + Location = "Submission Desk" + }, + new EventOccurrence + { + Name = "Competition 1", + Date = "March 16", + Time = "10:30 a.m.", + StartTime = new DateTime(2026, 3, 16, 10, 30, 0), + EndTime = new DateTime(2026, 3, 16, 12, 0, 0), + Location = "Competition Hall" + }, + new EventOccurrence + { + Name = "Competition 2", + Date = "March 16", + Time = "10:30 a.m.", + StartTime = new DateTime(2026, 3, 16, 11, 30, 0), + EndTime = new DateTime(2026, 3, 16, 13, 0, 0), + Location = "Competition Hall" + }, + new EventOccurrence + { + Name = "Awards Ceremony", + Date = "March 17", + Time = "2:00 p.m.", + StartTime = new DateTime(2026, 3, 17, 14, 0, 0), + EndTime = new DateTime(2026, 3, 17, 16, 0, 0), + Location = "Main Auditorium" + } + }; + + return Task.FromResult>(mockOccurrences); + } + + public Task> GetEventOccurrencesForDateRangeAsync(DateTime start, DateTime end) + { + return GetEventOccurrencesAsync().ContinueWith(task => + { + var allOccurrences = task.Result; + return allOccurrences.Where(eo => + eo.StartTime.Date >= start.Date && + eo.StartTime.Date <= end.Date); + }); + } +} + diff --git a/WebApp/Services/IEventOccurrenceService.cs b/WebApp/Services/IEventOccurrenceService.cs new file mode 100644 index 0000000..47a8f31 --- /dev/null +++ b/WebApp/Services/IEventOccurrenceService.cs @@ -0,0 +1,17 @@ +using Core.Entities; + +namespace WebApp.Services; + +public interface IEventOccurrenceService +{ + /// + /// Gets all event occurrences. + /// + Task> GetEventOccurrencesAsync(); + + /// + /// Gets event occurrences within the specified date range. + /// + Task> GetEventOccurrencesForDateRangeAsync(DateTime start, DateTime end); +} + diff --git a/WebApp/WebApp.csproj b/WebApp/WebApp.csproj index 08638d1..f938bcf 100644 --- a/WebApp/WebApp.csproj +++ b/WebApp/WebApp.csproj @@ -14,6 +14,7 @@ +