@inject IWorkDayService WorkDayService @inject IJSRuntime JS
@code { [Parameter] public DateOnly Date { get; set; } [Parameter] public string? EventId { get; set; } [Parameter] public EventCallback OnSaved { get; set; } [Parameter] public EventCallback OnClosed { get; set; } private bool loaded; private bool isExistingEvent; private DateOnly selectedDate; private string eventId = string.Empty; private CalendarEventType eventType = CalendarEventType.Generic; private string description = string.Empty; private string? startTimeStr; private string? endTimeStr; private DateOnly? endDate; private string? statusMessage; private string? loadKey; protected override async Task OnParametersSetAsync() { var nextKey = $"{Date:yyyy-MM-dd}|{EventId}"; if (nextKey == loadKey) { return; } loadKey = nextKey; loaded = false; selectedDate = Date; statusMessage = null; await LoadEventAsync(); loaded = true; } private async Task LoadEventAsync() { if (string.IsNullOrWhiteSpace(EventId)) { SetDefaults(); return; } var existing = await WorkDayService.GetCalendarEventAsync(selectedDate, EventId); if (existing is not null) { eventId = existing.Id; selectedDate = existing.StartDate == default ? selectedDate : existing.StartDate; eventType = existing.EventType; description = existing.Description; startTimeStr = existing.StartTime?.ToString("HH:mm"); endTimeStr = existing.EndTime?.ToString("HH:mm"); endDate = existing.EndDate; isExistingEvent = true; } else { SetDefaults(); statusMessage = "The selected calendar event was not found. A new event will be created."; } } private void SetDefaults() { eventId = string.Empty; eventType = CalendarEventType.Generic; description = string.Empty; startTimeStr = null; endTimeStr = null; endDate = null; isExistingEvent = false; } private Task OnDateChangedAsync(DateOnly? value) { if (value.HasValue) { selectedDate = value.Value; statusMessage = null; } return Task.CompletedTask; } private Task OnEndDateChangedAsync(DateOnly? value) { endDate = value; statusMessage = null; return Task.CompletedTask; } private Task OnStartTimeChanged(ChangeEventArgs e) { startTimeStr = e.Value?.ToString(); statusMessage = null; return Task.CompletedTask; } private Task OnEndTimeChanged(ChangeEventArgs e) { endTimeStr = e.Value?.ToString(); statusMessage = null; return Task.CompletedTask; } private async Task SaveAsync() { var calendarEvent = new CalendarEventDocument { Id = eventId, StartDate = selectedDate, EndDate = endDate, EventType = eventType, Description = description, StartTime = ParseTime(startTimeStr), EndTime = ParseTime(endTimeStr) }; await WorkDayService.SaveCalendarEventAsync(Date, calendarEvent); await OnSaved.InvokeAsync(); } private async Task DeleteAsync() { if (!isExistingEvent || string.IsNullOrWhiteSpace(eventId)) { return; } var eventName = CalendarEventFormatter.GetDisplayDescription(eventType, description); var confirmed = await JS.InvokeAsync("confirm", $"Delete calendar event '{eventName}' starting on {FormatDisplayDate(selectedDate)}?\nThis cannot be undone."); if (!confirmed) { return; } var deleted = await WorkDayService.DeleteCalendarEventAsync(Date, eventId); if (deleted) { await OnSaved.InvokeAsync(); return; } statusMessage = "Unable to delete the calendar event."; } private Task CloseAsync() => OnClosed.InvokeAsync(); private decimal? GetDuration() { var start = ParseTime(startTimeStr); var end = ParseTime(endTimeStr); if (!start.HasValue || !end.HasValue || end <= start) { return null; } return Math.Round((decimal)(end.Value - start.Value).TotalHours, 2, MidpointRounding.AwayFromZero); } private string FormatDuration() => GetDuration() is { } duration ? FormatDurationHours(duration) : "—"; private static string FormatDurationHours(decimal value) { var totalMinutes = (int)Math.Round(value * 60m, MidpointRounding.AwayFromZero); var hours = totalMinutes / 60; var minutes = totalMinutes % 60; return $"{hours:00}:{minutes:00}"; } private static TimeOnly? ParseTime(string? value) { return !string.IsNullOrWhiteSpace(value) && TimeOnly.TryParse(value, out var parsed) ? parsed : null; } private static string FormatDisplayDate(DateOnly date) { return date.ToString("dddd dd/MM/yyyy"); } }