@page "/calendar-event"
@page "/calendar-event/{DateStr}"
@page "/calendar-event/{DateStr}/{EventId}"
@attribute [Authorize]
@rendermode InteractiveServer
@inject IWorkDayService WorkDayService
@inject NavigationManager Navigation
@inject IJSRuntime JS
Calendar Event
Calendar Event
@if (!loaded)
{
Loading...
}
else
{
@if (isExistingEvent)
{
}
@if (!string.IsNullOrWhiteSpace(statusMessage))
{
@statusMessage
}
}
@code {
[Parameter] public string? DateStr { get; set; }
[Parameter] public string? EventId { get; set; }
private bool loaded;
private bool isExistingEvent;
private DateOnly selectedDate = DateOnly.FromDateTime(DateTime.Today);
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;
protected override async Task OnInitializedAsync()
{
if (!string.IsNullOrEmpty(DateStr) && DateOnly.TryParseExact(DateStr, "yyyy-MM-dd", out var parsed))
{
selectedDate = parsed;
}
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 for this day.";
}
}
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)
};
var saved = await WorkDayService.SaveCalendarEventAsync(selectedDate, calendarEvent);
eventId = saved.Id;
isExistingEvent = true;
startTimeStr = saved.StartTime?.ToString("HH:mm");
endTimeStr = saved.EndTime?.ToString("HH:mm");
Navigation.NavigateTo($"/calendar/{selectedDate:yyyy-MM}");
}
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(selectedDate, eventId);
if (deleted)
{
Navigation.NavigateTo($"/calendar/{selectedDate:yyyy-MM}");
return;
}
statusMessage = "Unable to delete the calendar event.";
}
private void BackToCalendar()
{
Navigation.NavigateTo($"/calendar/{selectedDate:yyyy-MM}");
}
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");
}
}