@page "/Calendar" @using Template.Shared.Core.Dto @using Template.Shared.Core.Interface @using Template.Shared.Components.Layout @using Template.Shared.Components.SingleElements @using Template.Shared.Components.Layout.Spinner @using Template.Shared.Components.Layout.BottomSheet @inject IManageDataService ManageData @inject IJSRuntime JS
@if (Expanded) { @foreach (var nomeGiorno in GiorniSettimana) {
@nomeGiorno
} @foreach (var unused in Enumerable.Range(0, StartOffset)) { } @for (var d = 1; d <= DaysInMonth; d++) { var day = new DateTime(CurrentMonth.Year, CurrentMonth.Month, d); var isSelected = IsSameDay(day, SelectedDate); var isToday = IsSameDay(day, DateTime.Today); var events = ReturnFilteredActivity(day);
@d
@if (events.Any()) {
@foreach (var cat in events.Select(x => x.Category).Distinct()) {
}
}
} @foreach (var unused in Enumerable.Range(0, EndOffset)) { } } else { @foreach (var day in DaysOfWeek) { var isSelected = IsSameDay(day, SelectedDate); var isToday = IsSameDay(day, DateTime.Today);
@day.ToString("ddd", new System.Globalization.CultureInfo("it-IT"))
@day.Day
@if (ReturnFilteredActivity(day).Any()) {
@foreach (var cat in ReturnFilteredActivity(day).Select(x => x.Category).Distinct()) {
}
}
} }
@if (IsLoading) { } else if (FilteredActivities is { Count: > 0 }) { } else { }
@code { // Stato UI private bool Expanded { get; set; } = false; private string SliderAnimation { get; set; } = string.Empty; private ElementReference weekSliderRef; private DotNetObjectReference? dotNetHelper; // Stato calendario private DateTime SelectedDate { get; set; } = DateTime.Today; private DateTime _internalMonth = DateTime.Today; private DateTime CurrentMonth => new(_internalMonth.Year, _internalMonth.Month, 1); // Stato attività private List MonthActivities { get; set; } = []; private List FilteredActivities { get; set; } = []; private bool IsLoading { get; set; } = true; // Supporto rendering mese private static readonly string[] GiorniSettimana = ["Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"]; private int DaysInMonth => DateTime.DaysInMonth(CurrentMonth.Year, CurrentMonth.Month); private int StartOffset => (int)CurrentMonth.DayOfWeek == 0 ? 6 : (int)CurrentMonth.DayOfWeek - 1; //Filtri private bool OpenFilter { get; set; } private FilterActivityDTO Filter { get; set; } = new(); private int EndOffset { get { var totalCells = (int)Math.Ceiling((DaysInMonth + StartOffset) / 7.0) * 7; return totalCells - (DaysInMonth + StartOffset); } } // Supporto rendering settimana private IEnumerable DaysOfWeek { get { var start = GetStartOfWeek(SelectedDate); return Enumerable.Range(0, 7).Select(i => start.AddDays(i)); } } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { Filter.User = new HashSet { UserSession.User.Username }; dotNetHelper = DotNetObjectReference.Create(this); await JS.InvokeVoidAsync("calendarSwipe.register", weekSliderRef, dotNetHelper); _internalMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1); await LoadMonthData(); if (!Expanded) ApplyFilter(); StateHasChanged(); } } [JSInvokable] public async Task OnSwipeLeft() { await CambiaPeriodo(1); StateHasChanged(); if (Expanded) { await LoadMonthData(); } } [JSInvokable] public async Task OnSwipeRight() { await CambiaPeriodo(-1); StateHasChanged(); if (Expanded) { await LoadMonthData(); } } [JSInvokable] public async Task OnSwipeDown() { if (!Expanded) ToggleExpanded(); } [JSInvokable] public async Task OnSwipeUp() { if (Expanded) ToggleExpanded(); } // Cambio periodo mese/settimana private async Task CambiaPeriodo(int direzione) { if (Expanded) { // Cambio solo il mese visualizzato, NON cambiare SelectedDate var y = CurrentMonth.Year; var m = CurrentMonth.Month + direzione; if (m < 1) { y--; m = 12; } if (m > 12) { y++; m = 1; } _internalMonth = new DateTime(y, m, 1); } else { // Cambio settimana: aggiorno anche il giorno selezionato await SelezionaData(SelectedDate.AddDays(7 * direzione)); _internalMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1); } } // Cambio modalità private void ToggleExpanded() { if (Expanded) { SliderAnimation = "collapse-animation"; StateHasChanged(); Expanded = false; } else { Expanded = true; SliderAnimation = "expand-animation"; StateHasChanged(); } SliderAnimation = ""; StateHasChanged(); } // Caricamento attività al cambio mese private async Task LoadMonthData() { IsLoading = true; StateHasChanged(); // Carica tutte le attività del mese corrente visualizzato var start = CurrentMonth; var end = start.AddDays(DaysInMonth - 1); var activities = await ManageData.GetActivity(x => (x.EffectiveDate == null && x.EstimatedDate >= start && x.EstimatedDate <= end) || (x.EffectiveDate >= start && x.EffectiveDate <= end)); MonthActivities = activities.OrderBy(x => x.EffectiveDate ?? x.EstimatedDate).ToList(); IsLoading = false; StateHasChanged(); } // Selezione giorno in settimana private async Task SelezionaData(DateTime day) { SelectedDate = day; StateHasChanged(); var cacheInternalMonth = _internalMonth; _internalMonth = new DateTime(day.Year, day.Month, 1); if (cacheInternalMonth != _internalMonth) { await LoadMonthData(); } ApplyFilter(); StateHasChanged(); } // Selezione giorno dal mese (chiude la vista mese!) private async Task SelezionaDataDalMese(DateTime day) { SelectedDate = day; ApplyFilter(); // Chiudi la vista mese e passa alla settimana, con animazione SliderAnimation = "collapse-animation"; StateHasChanged(); Expanded = false; _internalMonth = new DateTime(day.Year, day.Month, 1); // Sync il mese visualizzato SliderAnimation = ""; StateHasChanged(); } // Utility private static bool IsSameDay(DateTime d1, DateTime d2) => d1.Date == d2.Date; private static DateTime GetStartOfWeek(DateTime date) { var day = date.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)date.DayOfWeek; return date.AddDays(-day + 1).Date; } private List GetEventsForDay(DateTime day) => MonthActivities?.Where(x => (x.EffectiveDate ?? x.EstimatedDate) == day.Date).ToList() ?? []; public void Dispose() { dotNetHelper?.Dispose(); } private async Task OnActivityChanged(string activityId) { var newActivity = await ManageData.GetActivity(x => x.ActivityId.Equals(activityId)); var indexActivity = MonthActivities?.FindIndex(x => x.ActivityId.Equals(activityId)); if (indexActivity != null && !newActivity.IsNullOrEmpty()) { MonthActivities![indexActivity.Value] = newActivity[0]; } ApplyFilter(); StateHasChanged(); } private void ToggleFilter() { OpenFilter = !OpenFilter; StateHasChanged(); } private void ApplyFilter() { FilteredActivities = GetEventsForDay(SelectedDate); if (!Filter.ClearFilter) { FilteredActivities = GetEventsForDay(SelectedDate)? .Where(x => (!Filter.Text.IsNullOrEmpty() && x.ActivityDescription != null && x.ActivityDescription.ContainsIgnoreCase(Filter.Text!)) || (x.ActivityTypeId != null && !Filter.Type.IsNullOrEmpty() && x.ActivityTypeId.Equals(Filter.Type)) || (x.ActivityResultId != null && !Filter.Result.IsNullOrEmpty() && x.ActivityResultId.Equals(Filter.Result)) || (x.UserName != null && !Filter.User.IsNullOrEmpty() && Filter.User!.Contains(x.UserName)) || (Filter.Category != null && x.Category.Equals(Filter.Category)) ) .ToList() ?? []; } StateHasChanged(); } private List ReturnFilteredActivity(DateTime day) { if (!Filter.ClearFilter) { return GetEventsForDay(day)? .Where(x => (!Filter.Text.IsNullOrEmpty() && x.ActivityDescription != null && x.ActivityDescription.ContainsIgnoreCase(Filter.Text!)) || (x.ActivityTypeId != null && !Filter.Type.IsNullOrEmpty() && x.ActivityTypeId.Equals(Filter.Type)) || (x.ActivityResultId != null && !Filter.Result.IsNullOrEmpty() && x.ActivityResultId.Equals(Filter.Result)) || (x.UserName != null && !Filter.User.IsNullOrEmpty() && Filter.User!.Contains(x.UserName)) || (Filter.Category != null && x.Category.Equals(Filter.Category)) ) .ToList() ?? []; } return GetEventsForDay(day); } }