Integrate TeamMeetingHistoryService into Calendar component for enhanced meeting management
This commit updates the Calendar component to include the ITeamMeetingHistoryService, allowing for the loading and display of meeting histories alongside event occurrences. The calendar items are now wrapped in CalendarItemWrapper to accommodate both events and meetings. Additionally, error handling and logging are implemented to ensure robustness during the loading process. This enhancement improves the overall functionality and user experience of the calendar feature by providing a comprehensive view of both events and meetings.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
@using WebApp.Authentication
|
@using WebApp.Authentication
|
||||||
@using Core.Utility
|
@using Core.Utility
|
||||||
@inject IEventOccurrenceService EventOccurrenceService
|
@inject IEventOccurrenceService EventOccurrenceService
|
||||||
|
@inject ITeamMeetingHistoryService TeamMeetingHistoryService
|
||||||
@inject ILogger<Index> Logger
|
@inject ILogger<Index> Logger
|
||||||
@inject IDialogService DialogService
|
@inject IDialogService DialogService
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@
|
|||||||
</MudButton>
|
</MudButton>
|
||||||
</MudButtonGroup>
|
</MudButtonGroup>
|
||||||
|
|
||||||
<MudCalendar T="CalendarEventItem"
|
<MudCalendar T="CalendarItemWrapper"
|
||||||
Items="_calendarItems"
|
Items="_calendarItems"
|
||||||
View="_currentView"
|
View="_currentView"
|
||||||
CurrentDay="@_calendarDate"
|
CurrentDay="@_calendarDate"
|
||||||
@@ -76,7 +77,7 @@
|
|||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<CalendarEventItem>? _calendarItems;
|
private List<CalendarItemWrapper>? _calendarItems;
|
||||||
private DateTime _calendarDate = DateTime.Today;
|
private DateTime _calendarDate = DateTime.Today;
|
||||||
private CalendarView _currentView = CalendarView.Month;
|
private CalendarView _currentView = CalendarView.Month;
|
||||||
|
|
||||||
@@ -105,7 +106,9 @@
|
|||||||
// Load teams for all event definitions
|
// Load teams for all event definitions
|
||||||
var teamsByEventId = await EventOccurrenceService.GetTeamsByEventDefinitionIdsAsync(eventDefinitionIds);
|
var teamsByEventId = await EventOccurrenceService.GetTeamsByEventDefinitionIdsAsync(eventDefinitionIds);
|
||||||
|
|
||||||
List<CalendarEventItem> items = [];
|
List<CalendarItemWrapper> items = [];
|
||||||
|
|
||||||
|
// Add event occurrences
|
||||||
foreach (var occ in eventOccurrences)
|
foreach (var occ in eventOccurrences)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -127,8 +130,8 @@
|
|||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
var calendarItem = new CalendarEventItem(occ, studentFirstNames);
|
var calendarEventItem = new CalendarEventItem(occ, studentFirstNames);
|
||||||
items.Add(calendarItem);
|
items.Add(new CalendarItemWrapper(calendarEventItem));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -138,8 +141,37 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load and add meeting histories
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Loading meeting histories");
|
||||||
|
var meetingHistories = await TeamMeetingHistoryService.GetMeetingHistoriesAsync();
|
||||||
|
|
||||||
|
foreach (var meetingHistory in meetingHistories)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var calendarMeetingItem = new CalendarMeetingItem(meetingHistory);
|
||||||
|
items.Add(new CalendarItemWrapper(calendarMeetingItem));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError(ex, "Error creating CalendarMeetingItem for meeting history Id={Id}, Date={Date}",
|
||||||
|
meetingHistory?.Id, meetingHistory?.MeetingDate);
|
||||||
|
// Continue processing other items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInformation("Added {Count} meeting histories to calendar", meetingHistories.Count());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError(ex, "Error loading meeting histories");
|
||||||
|
// Continue - don't fail the entire calendar load if meetings fail
|
||||||
|
}
|
||||||
|
|
||||||
_calendarItems = items;
|
_calendarItems = items;
|
||||||
Logger.LogInformation("Created {Count} calendar items from {OccurrenceCount} occurrences",
|
Logger.LogInformation("Created {Count} calendar items from {OccurrenceCount} occurrences and meetings",
|
||||||
_calendarItems.Count, eventOccurrences.Count());
|
_calendarItems.Count, eventOccurrences.Count());
|
||||||
|
|
||||||
// Find the next date with events
|
// Find the next date with events
|
||||||
@@ -168,7 +200,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var today = DateTime.Today;
|
var today = DateTime.Today;
|
||||||
var nextEvent = _calendarItems
|
var nextItem = _calendarItems
|
||||||
.Where(item =>
|
.Where(item =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -184,17 +216,17 @@
|
|||||||
.OrderBy(item => item.Start)
|
.OrderBy(item => item.Start)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
if (nextEvent != null)
|
if (nextItem != null)
|
||||||
{
|
{
|
||||||
return nextEvent.Start.Date;
|
return nextItem.Start.Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to first event if no future events
|
// Fallback to first item if no future items
|
||||||
var firstEvent = _calendarItems
|
var firstItem = _calendarItems
|
||||||
.OrderBy(item => item.Start)
|
.OrderBy(item => item.Start)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
return firstEvent != null ? firstEvent.Start.Date : DateTime.Today;
|
return firstItem != null ? firstItem.Start.Date : DateTime.Today;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -235,12 +267,19 @@
|
|||||||
return string.Join("\n", parts);
|
return string.Join("\n", parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnItemClicked(CalendarEventItem calendarEventItem)
|
private async Task OnItemClicked(CalendarItemWrapper wrapper)
|
||||||
{
|
{
|
||||||
if (_calendarItems == null)
|
if (_calendarItems == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await ShowEventDetails(calendarEventItem);
|
if (wrapper.ItemType == CalendarItemType.Event && wrapper.EventItem != null)
|
||||||
|
{
|
||||||
|
await ShowEventDetails(wrapper.EventItem);
|
||||||
|
}
|
||||||
|
else if (wrapper.ItemType == CalendarItemType.Meeting && wrapper.MeetingItem != null)
|
||||||
|
{
|
||||||
|
await ShowMeetingDetails(wrapper.MeetingItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowEventDetails(CalendarEventItem item)
|
private async Task ShowEventDetails(CalendarEventItem item)
|
||||||
@@ -264,5 +303,25 @@
|
|||||||
|
|
||||||
await DialogService.ShowAsync<EventOccurrenceDetailsDialog>("Event Details", parameters, options);
|
await DialogService.ShowAsync<EventOccurrenceDetailsDialog>("Event Details", parameters, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ShowMeetingDetails(CalendarMeetingItem item)
|
||||||
|
{
|
||||||
|
if (item.MeetingHistoryData == null) return;
|
||||||
|
|
||||||
|
var parameters = new DialogParameters
|
||||||
|
{
|
||||||
|
["MeetingHistoryId"] = item.MeetingHistoryData.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
var options = new DialogOptions
|
||||||
|
{
|
||||||
|
CloseOnEscapeKey = true,
|
||||||
|
CloseButton = true,
|
||||||
|
MaxWidth = MaxWidth.Large,
|
||||||
|
FullWidth = true
|
||||||
|
};
|
||||||
|
|
||||||
|
await DialogService.ShowAsync<MeetingHistoryDetailDialog>("Meeting Details", parameters, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using Heron.MudCalendar;
|
||||||
|
|
||||||
|
namespace WebApp.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type discriminator for calendar item types.
|
||||||
|
/// </summary>
|
||||||
|
public enum CalendarItemType
|
||||||
|
{
|
||||||
|
Event,
|
||||||
|
Meeting
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wrapper class for calendar items that can hold either a CalendarEventItem or CalendarMeetingItem.
|
||||||
|
/// This allows MudCalendar to display mixed item types while maintaining type safety.
|
||||||
|
/// </summary>
|
||||||
|
public class CalendarItemWrapper : CalendarItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of calendar item this wrapper contains.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarItemType ItemType { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the wrapped CalendarEventItem if ItemType is Event, otherwise null.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarEventItem? EventItem { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the wrapped CalendarMeetingItem if ItemType is Meeting, otherwise null.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarMeetingItem? MeetingItem { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameterless constructor required by Heron.MudCalendar component.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarItemWrapper()
|
||||||
|
{
|
||||||
|
// Initialize base class properties to avoid null reference issues
|
||||||
|
Text = string.Empty;
|
||||||
|
Start = DateTime.MinValue;
|
||||||
|
End = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a wrapper for a CalendarEventItem.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarItemWrapper(CalendarEventItem eventItem)
|
||||||
|
{
|
||||||
|
ItemType = CalendarItemType.Event;
|
||||||
|
EventItem = eventItem;
|
||||||
|
// Delegate properties to wrapped item
|
||||||
|
Text = eventItem.Text;
|
||||||
|
Start = eventItem.Start;
|
||||||
|
End = eventItem.End;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a wrapper for a CalendarMeetingItem.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarItemWrapper(CalendarMeetingItem meetingItem)
|
||||||
|
{
|
||||||
|
ItemType = CalendarItemType.Meeting;
|
||||||
|
MeetingItem = meetingItem;
|
||||||
|
// Delegate properties to wrapped item
|
||||||
|
Text = meetingItem.Text;
|
||||||
|
Start = meetingItem.Start;
|
||||||
|
End = meetingItem.End;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Core.Entities;
|
||||||
|
using Heron.MudCalendar;
|
||||||
|
|
||||||
|
namespace WebApp.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calendar meeting item model for Heron.MudCalendar component.
|
||||||
|
/// Maps from TeamMeetingHistory entity to calendar event format.
|
||||||
|
/// </summary>
|
||||||
|
public class CalendarMeetingItem : CalendarItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the original TeamMeetingHistory data.
|
||||||
|
/// </summary>
|
||||||
|
public TeamMeetingHistory? MeetingHistoryData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parameterless constructor required by Heron.MudCalendar component.
|
||||||
|
/// </summary>
|
||||||
|
public CalendarMeetingItem()
|
||||||
|
{
|
||||||
|
// Initialize base class properties to avoid null reference issues
|
||||||
|
Text = string.Empty;
|
||||||
|
Start = DateTime.MinValue;
|
||||||
|
End = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalendarMeetingItem(TeamMeetingHistory meetingHistory)
|
||||||
|
{
|
||||||
|
MeetingHistoryData = meetingHistory;
|
||||||
|
// Set base class properties that the calendar component uses
|
||||||
|
Text = "Team Meeting";
|
||||||
|
// Use meeting date at 3:00 PM as default time
|
||||||
|
Start = meetingHistory.MeetingDate.Date.AddHours(15);
|
||||||
|
// Default to 1 hour duration
|
||||||
|
End = Start.AddHours(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user