From d6c7742501fef5d88ec7dce75dc08d1707a7c8d9 Mon Sep 17 00:00:00 2001 From: MarcoE Date: Mon, 16 Jun 2025 17:38:48 +0200 Subject: [PATCH] Vario --- .../Components/Pages/Calendar.razor | 338 +++++++++++++----- Template.Shared/Components/Pages/Login.razor | 57 ++- .../Components/Pages/Login.razor.css | 75 ++-- 3 files changed, 317 insertions(+), 153 deletions(-) diff --git a/Template.Shared/Components/Pages/Calendar.razor b/Template.Shared/Components/Pages/Calendar.razor index 0fe71a3..d31978f 100644 --- a/Template.Shared/Components/Pages/Calendar.razor +++ b/Template.Shared/Components/Pages/Calendar.razor @@ -8,35 +8,59 @@ @inject IManageDataService ManageData @inject IJSRuntime JS + - - -
- @if (Expanded) +
+ @if (Expanded) + { + + @foreach (var nomeGiorno in GiorniSettimana) { - - @foreach (var nomeGiorno in GiorniSettimana) +
+
@nomeGiorno
+
+ } + + @foreach (var unused in Enumerable.Range(0, StartOffset)) + { + + } + + @if (_isInitialized && _monthDaysData.Length > 0) + { + @for (var d = 1; d <= DaysInMonth; d++) { -
-
@nomeGiorno
+ var day = new DateTime(CurrentMonth.Year, CurrentMonth.Month, d); + var dayData = _monthDaysData[d - 1]; + +
+
@d
+ @if (dayData.HasEvents) + { +
+ @foreach (var cat in dayData.EventCategories) + { +
+ } +
+ }
} - - @foreach (var unused in Enumerable.Range(0, StartOffset)) - { - - } - + } + else + { + @* Fallback rendering per prima inizializzazione *@ @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); + var events = GetEventsForDay(day);
@@ -52,29 +76,64 @@ }
} + } - @foreach (var unused in Enumerable.Range(0, EndOffset)) + @foreach (var unused in Enumerable.Range(0, EndOffset)) + { + + } + } + else + { + + @if (_isInitialized && _weekDaysData.Length == 7 && _weekDaysData[0].Date != default) + { + @for (int i = 0; i < 7; i++) { - + var dayData = _weekDaysData[i]; + var day = dayData.Date; + +
+
@dayData.DayName
+
+
@day.Day
+ @if (dayData.HasEvents) + { +
+ @foreach (var cat in dayData.EventCategories) + { +
+ } +
+ } +
+
} } else { - - @foreach (var day in DaysOfWeek) + var start = GetStartOfWeek(SelectedDate); + var culture = new System.Globalization.CultureInfo("it-IT"); + + + for (var i = 0; i < 7; i++) { + var day = start.AddDays(i); var isSelected = IsSameDay(day, SelectedDate); var isToday = IsSameDay(day, DateTime.Today); + var events = GetEventsForDay(day);
-
@day.ToString("ddd", new System.Globalization.CultureInfo("it-IT"))
+
@day.ToString("ddd", culture)
+ @onclick="() => SelezionaData(day)" + aria-label="@day.ToString("dddd d MMMM", culture)">
@day.Day
- @if (ReturnFilteredActivity(day).Any()) + @if (events.Any()) {
- @foreach (var cat in ReturnFilteredActivity(day).Select(x => x.Category).Distinct()) + @foreach (var cat in events.Select(x => x.Category).Distinct()) {
} @@ -84,22 +143,23 @@
} } -
+ } +
@if (IsLoading) { - + } else if (FilteredActivities is { Count: > 0 }) { - + } else { - + }
@@ -107,6 +167,19 @@ @code { + // Modelli per ottimizzazione rendering + private record DayData(DateTime Date, string CssClass, bool HasEvents, CategoryData[] EventCategories, string DayName = ""); + + private record CategoryData(string CssClass, string Title); + + // Cache per rendering + private DayData[] _monthDaysData = Array.Empty(); + private DayData[] _weekDaysData = new DayData[7]; + private string _headerTitle = string.Empty; + private Dictionary> _eventsCache = new(); + private Dictionary _categoriesCache = new(); + private bool _isInitialized = false; + // Stato UI private bool Expanded { get; set; } = false; private string SliderAnimation { get; set; } = string.Empty; @@ -141,16 +214,6 @@ } } - // 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) @@ -162,17 +225,141 @@ _internalMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1); await LoadMonthData(); - if (!Expanded) - ApplyFilter(); - + PrepareRenderingData(); + _isInitialized = true; + ApplyFilter(); StateHasChanged(); } } + // Metodo per preparare i dati di rendering una sola volta + private void PrepareRenderingData() + { + PrepareHeaderTitle(); + PrepareEventsCache(); + + if (Expanded) + { + PrepareMonthDaysData(); + } + else + { + PrepareWeekDaysData(); + } + } + + private void PrepareHeaderTitle() + { + _headerTitle = CurrentMonth.ToString("MMMM yyyy", new System.Globalization.CultureInfo("it-IT")).FirstCharToUpper(); + } + + private void PrepareEventsCache() + { + _eventsCache.Clear(); + _categoriesCache.Clear(); + + // Raggruppa le attività per data + var activitiesByDate = MonthActivities + .GroupBy(x => (x.EffectiveDate ?? x.EstimatedDate!).Value.Date) + .ToDictionary(g => g.Key, g => g.ToList()); + + foreach (var (date, activities) in activitiesByDate) + { + _eventsCache[date] = activities; + + // Pre-calcola le categorie per ogni giorno + var categories = activities + .Select(x => x.Category) + .Distinct() + .Select(cat => new CategoryData(cat.ConvertToHumanReadable(), cat.ConvertToHumanReadable())) + .ToArray(); + + _categoriesCache[date] = categories; + } + } + + private void PrepareMonthDaysData() + { + _monthDaysData = new DayData[DaysInMonth]; + var today = DateTime.Today; + + for (int d = 1; d <= DaysInMonth; d++) + { + var day = new DateTime(CurrentMonth.Year, CurrentMonth.Month, d); + var isSelected = day.Date == SelectedDate.Date; + var isToday = day.Date == today; + + var cssClass = isSelected ? "selected" : (isToday ? "today" : ""); + var hasEvents = _eventsCache.ContainsKey(day.Date); + var eventCategories = hasEvents ? GetFilteredCategoriesForDay(day.Date) : Array.Empty(); + + _monthDaysData[d - 1] = new DayData(day, cssClass, eventCategories.Length > 0, eventCategories); + } + } + + private void PrepareWeekDaysData() + { + var start = GetStartOfWeek(SelectedDate); + var today = DateTime.Today; + var culture = new System.Globalization.CultureInfo("it-IT"); + + for (int i = 0; i < 7; i++) + { + var day = start.AddDays(i); + var isSelected = day.Date == SelectedDate.Date; + var isToday = day.Date == today; + + var cssClass = isSelected ? "selected" : (isToday ? "today" : ""); + var dayName = day.ToString("ddd", culture); + var hasEvents = _eventsCache.ContainsKey(day.Date); + var eventCategories = hasEvents ? GetFilteredCategoriesForDay(day.Date) : Array.Empty(); + + _weekDaysData[i] = new DayData(day, cssClass, eventCategories.Length > 0, eventCategories, dayName); + } + } + + private CategoryData[] GetFilteredCategoriesForDay(DateTime date) + { + if (!_categoriesCache.TryGetValue(date, out var categories)) + return Array.Empty(); + + if (Filter.ClearFilter) + return categories; + + // Applica i filtri alle categorie + var filteredActivities = GetFilteredActivitiesForDay(date); + if (!filteredActivities.Any()) + return Array.Empty(); + + return filteredActivities + .Select(x => x.Category) + .Distinct() + .Select(cat => new CategoryData(cat.ConvertToHumanReadable(), cat.ConvertToHumanReadable())) + .ToArray(); + } + + private List GetFilteredActivitiesForDay(DateTime date) + { + if (!_eventsCache.TryGetValue(date, out var activities)) + return new List(); + + if (Filter.ClearFilter) + return activities; + + return activities.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(); + } + [JSInvokable] public async Task OnSwipeLeft() { await CambiaPeriodo(1); + PrepareRenderingData(); StateHasChanged(); if (Expanded) { @@ -184,6 +371,7 @@ public async Task OnSwipeRight() { await CambiaPeriodo(-1); + PrepareRenderingData(); StateHasChanged(); if (Expanded) { @@ -210,7 +398,6 @@ { if (Expanded) { - // Cambio solo il mese visualizzato, NON cambiare SelectedDate var y = CurrentMonth.Year; var m = CurrentMonth.Month + direzione; if (m < 1) @@ -229,7 +416,6 @@ } else { - // Cambio settimana: aggiorno anche il giorno selezionato await SelezionaData(SelectedDate.AddDays(7 * direzione)); _internalMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1); } @@ -241,16 +427,17 @@ if (Expanded) { SliderAnimation = "collapse-animation"; - StateHasChanged(); Expanded = false; } else { Expanded = true; SliderAnimation = "expand-animation"; - StateHasChanged(); } + PrepareRenderingData(); + StateHasChanged(); + SliderAnimation = ""; StateHasChanged(); } @@ -261,7 +448,6 @@ 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 => @@ -269,6 +455,7 @@ (x.EffectiveDate >= start && x.EffectiveDate <= end)); MonthActivities = activities.OrderBy(x => x.EffectiveDate ?? x.EstimatedDate).ToList(); + PrepareRenderingData(); IsLoading = false; StateHasChanged(); } @@ -277,7 +464,6 @@ private async Task SelezionaData(DateTime day) { SelectedDate = day; - StateHasChanged(); var cacheInternalMonth = _internalMonth; _internalMonth = new DateTime(day.Year, day.Month, 1); @@ -286,6 +472,10 @@ { await LoadMonthData(); } + else + { + PrepareRenderingData(); + } ApplyFilter(); StateHasChanged(); @@ -295,12 +485,14 @@ 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 + _internalMonth = new DateTime(day.Year, day.Month, 1); + + PrepareRenderingData(); + ApplyFilter(); + StateHasChanged(); + SliderAnimation = ""; StateHasChanged(); } @@ -315,7 +507,7 @@ } private List GetEventsForDay(DateTime day) - => MonthActivities?.Where(x => (x.EffectiveDate ?? x.EstimatedDate) == day.Date).ToList() ?? []; + => _eventsCache.TryGetValue(day.Date, out var events) ? events : new List(); public void Dispose() { @@ -330,6 +522,7 @@ if (indexActivity != null && !newActivity.IsNullOrEmpty()) { MonthActivities![indexActivity.Value] = newActivity[0]; + PrepareRenderingData(); // Ricalcola i dati di rendering } ApplyFilter(); @@ -344,40 +537,25 @@ private void ApplyFilter() { - FilteredActivities = GetEventsForDay(SelectedDate); + FilteredActivities = GetFilteredActivitiesForDay(SelectedDate); - if (!Filter.ClearFilter) + // Aggiorna i dati di rendering se il filtro è cambiato + if (Expanded) { - 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() ?? []; + PrepareMonthDaysData(); + } + else + { + PrepareWeekDaysData(); } StateHasChanged(); } + // Metodo ottimizzato per il rendering dei filtri 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); + return GetFilteredActivitiesForDay(day); } } \ No newline at end of file diff --git a/Template.Shared/Components/Pages/Login.razor b/Template.Shared/Components/Pages/Login.razor index f25980a..b319086 100644 --- a/Template.Shared/Components/Pages/Login.razor +++ b/Template.Shared/Components/Pages/Login.razor @@ -10,41 +10,34 @@ } else { -
-
- -
- Nome App -
- -
-
-
- -
-
- -
-
- -
-
- -
+ } diff --git a/Template.Shared/Components/Pages/Login.razor.css b/Template.Shared/Components/Pages/Login.razor.css index a2610c3..f7c0617 100644 --- a/Template.Shared/Components/Pages/Login.razor.css +++ b/Template.Shared/Components/Pages/Login.razor.css @@ -1,46 +1,44 @@ -.center-box { - margin-top: -1.1rem !important; /* remove page padding */ +.login-page { + height: 100%; + display: flex; + flex-direction: column; + background: hsl(from var(--mud-palette-primary) h s 96%); } -.box-area { - width: 930px; -} - -.right-box { - padding: 15px 30px 0 30px; -} - -::placeholder { - font-size: 16px; -} - -.rounded-4 { - border-radius: 20px; -} - -.rounded-5 { - border-radius: 30px; -} - -.bg-white { - background: var(--mud-palette-surface) !important; -} - -.appName { - margin-top: 15px; - font-size: large; +.container-top-logo > span { + font-size: x-large; font-weight: 900; color: var(--mud-palette-primary) } -.button-login { +.container-login > span { + font-size: large; + font-weight: 900; text-align: center; - background-color: var(--mud-palette-primary); - border-radius: 6px; - padding: .3rem 2rem; - width: 100%; - font-weight: 700; - color: var(--mud-palette-appbar-text); +} + +.container-top-logo { + height: 35vh; + display: flex; + align-items: center; + justify-content: center; +} + +.login-form-container { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.container-login { + background: var(--mud-palette-surface); + border-top-left-radius: 16px; + border-top-right-radius: 16px; + height: 100%; + display: flex; + flex-direction: column; + padding: 4px 16px 16px; + box-shadow: 0 -2px 10px rgba(165, 165, 165, 0.5); } .login-footer { @@ -57,9 +55,4 @@ .login-footer img { height: 15px; margin-left: 4px; -} - -.container > .bg-white { - box-shadow: var(--card-shadow); - border: 1px solid var(--card-border-color); } \ No newline at end of file