Cambiata visualizzazione calendario e aggiunto formAttività
This commit is contained in:
@@ -1,180 +1,302 @@
|
||||
@page "/Calendar"
|
||||
@attribute [Authorize]
|
||||
@page "/Calendar"
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Interface
|
||||
@using Template.Shared.Components.Layout
|
||||
@using Template.Shared.Components.SingleElements.Calendar
|
||||
@using Template.Shared.Components.SingleElements
|
||||
@using Template.Shared.Components.Layout.Spinner
|
||||
@inject IManageDataService manageData
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<HeaderLayout Title="Agenda" ShowFilter="true"/>
|
||||
<HeaderLayout Title="@CurrentMonth.ToString("MMMM yyyy", new System.Globalization.CultureInfo("it-IT")).FirstCharToUpper()"
|
||||
ShowFilter="true"
|
||||
ShowCalendarToggle="true"
|
||||
OnCalendarToggle="ToggleExpanded"/>
|
||||
|
||||
<div class="content">
|
||||
<MudButtonGroup Size="Size.Small" Class="custom-mudButtonGroup" Color="Color.Surface" OverrideStyles="true" Variant="Variant.Outlined" DropShadow="true">
|
||||
<MudButton StartIcon="@Icons.Material.Filled.ViewStream" Class="@(FilterByDay ? "custom-button-active" : "")" OnClick="SelectDay">Giorno</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.CalendarViewDay" Class="@(FilterByWeek ? "custom-button-active" : "")" OnClick="SelectWeek">Settimana</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.CalendarViewMonth" Class="@(FilterByMonth ? "custom-button-active" : "")" OnClick="SelectMonth">Mese</MudButton>
|
||||
</MudButtonGroup>
|
||||
<div @ref="weekSliderRef" class="week-slider @(Expanded ? "expanded" : "") @(SliderAnimation)">
|
||||
@if (Expanded)
|
||||
{
|
||||
<!-- Vista mensile -->
|
||||
@foreach (var nomeGiorno in GiorniSettimana)
|
||||
{
|
||||
<div class="week-day">
|
||||
<div>@nomeGiorno</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="activity-filter">
|
||||
<div class="date-controller">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.ChevronLeft" @onclick="() => ChangeDate(-1)" Color="Color.Surface"/>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Surface" OnClick="OpenCalendar">
|
||||
@if (FilterByDay)
|
||||
@foreach (var unused in Enumerable.Range(0, StartOffset))
|
||||
{
|
||||
<div class="day" style="visibility: hidden"></div>
|
||||
}
|
||||
|
||||
@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 = GetEventsForDay(day);
|
||||
|
||||
<div class="day @(isSelected ? "selected" : (isToday ? "today" : ""))"
|
||||
@onclick="() => SelezionaDataDalMese(day)">
|
||||
<div>@d</div>
|
||||
@if (events.Any())
|
||||
{
|
||||
@($"{DateFilter:M}")
|
||||
<div class="event-dot-container" style="margin-top: 2px;">
|
||||
@foreach (var cat in events.Select(x => x.Category).Distinct())
|
||||
{
|
||||
<div class="event-dot @cat.ConvertToHumanReadable()" title="@cat.ConvertToHumanReadable()"></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else if (FilterByWeek)
|
||||
{
|
||||
@($"{(DateRangeFilter.Start!.Value.Month == DateRangeFilter.End!.Value.Month ? DateRangeFilter.Start!.Value.Day : DateRangeFilter.Start!.Value.ToString("M"))} - {DateRangeFilter.End!.Value:M}")
|
||||
}
|
||||
else if (FilterByMonth)
|
||||
{
|
||||
@($"{DateFilter:Y}")
|
||||
}
|
||||
</MudButton>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.ChevronRight" @onclick="() => ChangeDate(1)" Color="Color.Surface"/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<MudOverlay @bind-Visible="_isVisible" DarkBackground="true" AutoClose="true">
|
||||
<MudDatePicker @bind-Date:after="CloseDatePicker" @bind-Date="DateFilter" PickerVariant="PickerVariant.Static">
|
||||
<PickerActions>
|
||||
@if (DateFilter != DateTime.Today)
|
||||
@foreach (var unused in Enumerable.Range(0, EndOffset))
|
||||
{
|
||||
<div class="day" style="visibility: hidden"></div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Vista settimanale -->
|
||||
@foreach (var day in DaysOfWeek)
|
||||
{
|
||||
var isSelected = IsSameDay(day, SelectedDate);
|
||||
var isToday = IsSameDay(day, DateTime.Today);
|
||||
|
||||
<div class="week-day">
|
||||
<div>@day.ToString("ddd", new System.Globalization.CultureInfo("it-IT"))</div>
|
||||
<div class="day @(isSelected ? "selected" : (isToday ? "today" : ""))"
|
||||
@onclick="() => SelezionaData(day)">
|
||||
<div>@day.Day</div>
|
||||
@if (GetEventsForDay(day).Any())
|
||||
{
|
||||
<MudButton Class="mr-auto align-self-start" OnClick="() => DateFilter = DateTime.Today">Oggi</MudButton>
|
||||
<div class="event-dot-container" style="margin-top: 2px;">
|
||||
@foreach (var cat in GetEventsForDay(day).Select(x => x.Category).Distinct())
|
||||
{
|
||||
<div class="event-dot @cat.ConvertToHumanReadable()" title="@cat.ConvertToHumanReadable()"></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</PickerActions>
|
||||
</MudDatePicker>
|
||||
</MudOverlay>
|
||||
</div>
|
||||
|
||||
<div class="card-container">
|
||||
@if (FilterByDay)
|
||||
{
|
||||
<DayView @bind-Date="DateFilter"/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else if (FilterByWeek)
|
||||
{
|
||||
<WeekView @bind-Date="DateRangeFilter" />
|
||||
}
|
||||
else if (FilterByMonth)
|
||||
{
|
||||
<MonthView @bind-Date="DateTimeForMonthView"/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<MudMenu PopoverClass="custom_popover" Class="custom-mudfab" AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomRight">
|
||||
<ActivatorContent>
|
||||
<MudFab Color="Color.Primary" Size="Size.Small" StartIcon="@Icons.Material.Filled.Add"/>
|
||||
</ActivatorContent>
|
||||
<ChildContent>
|
||||
<MudMenuItem>Nuovo contatto</MudMenuItem>
|
||||
<MudMenuItem>Nuova attivit<69></MudMenuItem>
|
||||
</ChildContent>
|
||||
</MudMenu>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="appointments">
|
||||
@if (IsLoading)
|
||||
{
|
||||
<SpinnerLayout FullScreen="false"/>
|
||||
}
|
||||
else if (FilteredActivities is { Count: > 0 })
|
||||
{
|
||||
@foreach (var activity in FilteredActivities)
|
||||
{
|
||||
<ActivityCard Activity="activity"/>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<NoDataAvailable Text="Nessuna attività trovata" ImageSource="_content/Template.Shared/images/undraw_file-search_cbur.svg"/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<MudMenu PopoverClass="custom_popover" Class="custom-mudfab" AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomRight">
|
||||
<ActivatorContent>
|
||||
<MudFab Color="Color.Primary" Size="Size.Small" StartIcon="@Icons.Material.Filled.Add"/>
|
||||
</ActivatorContent>
|
||||
<ChildContent>
|
||||
<MudMenuItem>Nuovo contatto</MudMenuItem>
|
||||
<MudMenuItem OnClick="OpenActivityForm">Nuova attività</MudMenuItem>
|
||||
</ChildContent>
|
||||
</MudMenu>
|
||||
|
||||
@code {
|
||||
private bool FilterByDay { get; set; } = true;
|
||||
private bool FilterByWeek { get; set; }
|
||||
private bool FilterByMonth { get; set; }
|
||||
private DateTime? DateFilter { get; set; } = DateTime.Today;
|
||||
private DateRange DateRangeFilter { get; set; } = new();
|
||||
private DateTime DateTimeForMonthView { get; set; }
|
||||
|
||||
private bool _isVisible;
|
||||
// Stato UI
|
||||
private bool Expanded { get; set; } = false;
|
||||
private string SliderAnimation { get; set; } = string.Empty;
|
||||
private ElementReference weekSliderRef;
|
||||
private DotNetObjectReference<Calendar>? dotNetHelper;
|
||||
|
||||
protected override void OnInitialized()
|
||||
// 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<ActivityDTO> MonthActivities { get; set; } = [];
|
||||
private List<ActivityDTO> 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;
|
||||
|
||||
private int EndOffset
|
||||
{
|
||||
CalcDateRange();
|
||||
}
|
||||
|
||||
public void OpenCalendar()
|
||||
{
|
||||
_isVisible = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void SelectDay()
|
||||
{
|
||||
ResetFilterCalendar();
|
||||
FilterByDay = !FilterByDay;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void SelectWeek()
|
||||
{
|
||||
ResetFilterCalendar();
|
||||
FilterByWeek = !FilterByWeek;
|
||||
CalcDateRange();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void SelectMonth()
|
||||
{
|
||||
ResetFilterCalendar();
|
||||
FilterByMonth = !FilterByMonth;
|
||||
DateTimeForMonthView = new DateTime(DateFilter!.Value.Year, DateFilter!.Value.Month, 1);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void ResetFilterCalendar(bool forceSelectDay = false)
|
||||
{
|
||||
FilterByDay = false;
|
||||
FilterByWeek = false;
|
||||
FilterByMonth = false;
|
||||
}
|
||||
|
||||
private void ChangeDate(int value)
|
||||
{
|
||||
var date = DateFilter!.Value;
|
||||
|
||||
if (FilterByDay)
|
||||
get
|
||||
{
|
||||
DateFilter = date.AddDays(value);
|
||||
var totalCells = (int)Math.Ceiling((DaysInMonth + StartOffset) / 7.0) * 7;
|
||||
return totalCells - (DaysInMonth + StartOffset);
|
||||
}
|
||||
else if (FilterByWeek)
|
||||
{
|
||||
DateFilter = DateRangeFilter.Start!.Value.AddDays(value > 0 ? 7 : -7);
|
||||
}
|
||||
else if (FilterByMonth)
|
||||
{
|
||||
var year = date.Year;
|
||||
var month = value > 0 ? date.Month + 1 : date.Month - 1;
|
||||
}
|
||||
|
||||
switch (month)
|
||||
// Supporto rendering settimana
|
||||
private IEnumerable<DateTime> 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)
|
||||
{
|
||||
dotNetHelper = DotNetObjectReference.Create(this);
|
||||
await JS.InvokeVoidAsync("calendarSwipe.register", weekSliderRef, dotNetHelper);
|
||||
_internalMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1);
|
||||
await LoadMonthData();
|
||||
}
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task OnSwipeLeft()
|
||||
{
|
||||
CambiaPeriodo(1);
|
||||
await LoadMonthData();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task OnSwipeRight()
|
||||
{
|
||||
CambiaPeriodo(-1);
|
||||
await LoadMonthData();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
// Cambio periodo mese/settimana
|
||||
private void 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)
|
||||
{
|
||||
case > 12:
|
||||
year++;
|
||||
month = 1;
|
||||
break;
|
||||
case < 1:
|
||||
year--;
|
||||
month = 12;
|
||||
break;
|
||||
y--;
|
||||
m = 12;
|
||||
}
|
||||
|
||||
DateFilter = new DateTime(year, month, 1);
|
||||
DateTimeForMonthView = DateFilter.Value;
|
||||
if (m > 12)
|
||||
{
|
||||
y++;
|
||||
m = 1;
|
||||
}
|
||||
|
||||
_internalMonth = new DateTime(y, m, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cambio settimana: aggiorno anche il giorno selezionato
|
||||
SelectedDate = SelectedDate.AddDays(7 * direzione);
|
||||
_internalMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Cambio modalità
|
||||
private async Task ToggleExpanded()
|
||||
{
|
||||
if (Expanded)
|
||||
{
|
||||
SliderAnimation = "collapse-animation";
|
||||
StateHasChanged();
|
||||
Expanded = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Expanded = true;
|
||||
SliderAnimation = "expand-animation";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
CalcDateRange();
|
||||
SliderAnimation = "";
|
||||
StateHasChanged();
|
||||
await LoadMonthData();
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// Filtro per il giorno selezionato (solo se il giorno selezionato è visibile nel mese corrente)
|
||||
if (SelectedDate.Month == CurrentMonth.Month && SelectedDate.Year == CurrentMonth.Year)
|
||||
FilteredActivities = GetEventsForDay(SelectedDate);
|
||||
else
|
||||
FilteredActivities = [];
|
||||
|
||||
IsLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void CalcDateRange()
|
||||
// Selezione giorno in settimana
|
||||
private void SelezionaData(DateTime day)
|
||||
{
|
||||
var giornoSettimana = DateFilter!.Value.DayOfWeek;
|
||||
var diffInizio = (7 + (giornoSettimana - DayOfWeek.Monday)) % 7;
|
||||
|
||||
DateRangeFilter.Start = DateFilter!.Value.AddDays(-diffInizio).Date;
|
||||
DateRangeFilter.End = DateRangeFilter.Start.Value.AddDays(6);
|
||||
}
|
||||
|
||||
private async Task CloseDatePicker()
|
||||
{
|
||||
DateTimeForMonthView = new DateTime(DateFilter!.Value.Year, DateFilter!.Value.Month, 1);
|
||||
CalcDateRange();
|
||||
await Task.Delay(150);
|
||||
|
||||
_isVisible = false;
|
||||
SelectedDate = day;
|
||||
_internalMonth = new DateTime(day.Year, day.Month, 1); // Sync il mese visualizzato solo se cambio settimana!
|
||||
FilteredActivities = GetEventsForDay(day);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
// Selezione giorno dal mese (chiude la vista mese!)
|
||||
private async Task SelezionaDataDalMese(DateTime day)
|
||||
{
|
||||
SelectedDate = day;
|
||||
FilteredActivities = GetEventsForDay(day);
|
||||
// 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();
|
||||
await LoadMonthData(); // Aggiorna anche la lista attività (se hai cambiato mese)
|
||||
}
|
||||
|
||||
// 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<ActivityDTO> GetEventsForDay(DateTime day)
|
||||
=> MonthActivities?.Where(x => (x.EffectiveDate ?? x.EstimatedDate) == day.Date).ToList() ?? [];
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
dotNetHelper?.Dispose();
|
||||
}
|
||||
|
||||
private void OpenActivityForm() =>
|
||||
NavigationManager.NavigateTo("/activity");
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user