Cambiata visualizzazione calendario e aggiunto formAttività
This commit is contained in:
@@ -5,24 +5,42 @@
|
||||
@if (Back)
|
||||
{
|
||||
<div class="left-section">
|
||||
<MudButton StartIcon="@Icons.Material.Outlined.ArrowBackIosNew"
|
||||
<MudButton StartIcon="@(!Cancel ? Icons.Material.Outlined.ArrowBackIosNew : "")"
|
||||
OnClick="GoBack"
|
||||
Color="Color.Info"
|
||||
Style="text-transform: none"
|
||||
Variant="Variant.Text">@BackTo</MudButton>
|
||||
Variant="Variant.Text">
|
||||
@BackTo
|
||||
</MudButton>
|
||||
</div>
|
||||
}
|
||||
|
||||
<h3 class="page-title">@Title</h3>
|
||||
|
||||
<div class="right-section">
|
||||
@if (ShowFilter)
|
||||
@if (LabelSave.IsNullOrEmpty())
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.FilterAlt" Color="Color.Dark" />
|
||||
@if (ShowFilter)
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.FilterAlt" Color="Color.Dark"/>
|
||||
}
|
||||
@if (ShowNotifications)
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Notifications" Color="Color.Dark"/>
|
||||
}
|
||||
@if (ShowCalendarToggle)
|
||||
{
|
||||
<MudIconButton OnClick="OnCalendarToggle" Icon="@Icons.Material.Filled.CalendarMonth" Color="Color.Dark"/>
|
||||
}
|
||||
}
|
||||
@if (ShowNotifications)
|
||||
else
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Notifications" Color="Color.Dark" />
|
||||
<MudButton OnClick="OnSave"
|
||||
Color="Color.Info"
|
||||
Style="text-transform: none"
|
||||
Variant="Variant.Text">
|
||||
@LabelSave
|
||||
</MudButton>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -35,6 +53,19 @@
|
||||
[Parameter] public bool Back { get; set; }
|
||||
[Parameter] public string BackTo { get; set; } = "";
|
||||
|
||||
[Parameter] public bool Cancel { get; set; }
|
||||
[Parameter] public string? LabelSave { get; set; }
|
||||
[Parameter] public EventCallback OnSave { get; set; }
|
||||
|
||||
[Parameter] public bool ShowCalendarToggle { get; set; }
|
||||
[Parameter] public EventCallback OnCalendarToggle { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
Back = !Back ? !Back && Cancel : Back;
|
||||
BackTo = Cancel ? "Annulla" : BackTo;
|
||||
}
|
||||
|
||||
private async Task GoBack()
|
||||
{
|
||||
await JS.InvokeVoidAsync("goBack");
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.left-section ::deep button {
|
||||
font-size: 1rem;
|
||||
.left-section ::deep button, .right-section ::deep button {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.left-section ::deep .mud-button-icon-start {
|
||||
|
||||
157
Template.Shared/Components/Pages/ActivityForm.razor
Normal file
157
Template.Shared/Components/Pages/ActivityForm.razor
Normal file
@@ -0,0 +1,157 @@
|
||||
@page "/activity"
|
||||
@page "/activity/{Id}"
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Components.Layout
|
||||
@using Template.Shared.Core.Interface
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<HeaderLayout Cancel="true" LabelSave="@LabelSave" ShowNotifications="false" Title="@(IsNew ? "Nuova" : $"{ActivityModel.ActivityId}")"/>
|
||||
|
||||
<div class="content">
|
||||
<div class="input-card">
|
||||
<MudTextField T="string?" Placeholder="Descrizione" Variant="Variant.Text" Lines="3" @bind-Value="ActivityModel.ActivityDescription" @bind-Value:after="OnAfterChangeValue"/>
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<div class="form-container">
|
||||
<MudInput T="string?" Placeholder="Cliente" @bind-Value="ActivityModel.Cliente" @bind-Value:after="OnAfterChangeValue"/>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<MudInput T="string?" Placeholder="Commessa" @bind-Value="ActivityModel.Commessa" @bind-Value:after="OnAfterChangeValue"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<div class="form-container">
|
||||
<span>Inizio</span>
|
||||
|
||||
<MudTextField T="DateTime?" Format="yyyy-MM-ddTHH:mm" InputType="InputType.DateTimeLocal" @bind-Value="ActivityModel.EstimatedTime" @bind-Value:after="OnAfterChangeValue"/>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span>Fine</span>
|
||||
|
||||
<MudTextField T="DateTime?" Format="yyyy-MM-ddTHH:mm" InputType="InputType.DateTimeLocal" @bind-Value="ActivityModel.EstimatedEndtime" @bind-Value:after="OnAfterChangeValue"/>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span>Avviso</span>
|
||||
|
||||
<MudSwitch T="bool" Disabled="true" Color="Color.Primary"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<div class="form-container text-align-end">
|
||||
<span>Assegnata a</span>
|
||||
|
||||
<MudInput T="string" Placeholder="Nessuno" @bind-Value="ActivityModel.UserName" @bind-Value:after="OnAfterChangeValue"/>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span>Tipo</span>
|
||||
|
||||
<MudSelect T="string?" Variant="Variant.Text" @bind-Value="ActivityModel.ActivityTypeId" @bind-Value:after="OnAfterChangeValue" Class="customIcon-select" AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var state in ActivityResult)
|
||||
{
|
||||
<MudSelectItem Value="@state">@state</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span>Esito</span>
|
||||
|
||||
<MudSelect T="string?" Variant="Variant.Text" @bind-Value="ActivityModel.ActivityResultId" @bind-Value:after="OnAfterChangeValue" Class="customIcon-select" AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var state in ActivityResult)
|
||||
{
|
||||
<MudSelectItem Value="@state">@state</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<MudTextField T="string?" Placeholder="Note" Variant="Variant.Text" Lines="4" @bind-Value="ActivityModel.Note" @bind-Value:after="OnAfterChangeValue" />
|
||||
</div>
|
||||
|
||||
<MudOverlay @bind-Visible="_selectEstimatedTime" DarkBackground="true" AutoClose="true">
|
||||
<MudDatePicker @bind-Date:after="CloseDatePicker" @bind-Date="ActivityModel.EstimatedTime" PickerVariant="PickerVariant.Static"/>
|
||||
</MudOverlay>
|
||||
|
||||
<MudOverlay @bind-Visible="_selectEstimatedEndTime" DarkBackground="true" AutoClose="true">
|
||||
<MudDatePicker @bind-Date:after="CloseDatePicker" @bind-Date="ActivityModel.EstimatedEndtime" PickerVariant="PickerVariant.Static"/>
|
||||
</MudOverlay>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string? Id { get; set; }
|
||||
|
||||
private ActivityDTO OriginalModel { get; set; } = new();
|
||||
private ActivityDTO ActivityModel { get; set; } = new();
|
||||
private List<ActivityResultDTO> ActivityResult { get; set; } = [];
|
||||
|
||||
private bool IsNew => Id.IsNullOrEmpty();
|
||||
private bool _selectEstimatedTime;
|
||||
private bool _selectEstimatedEndTime;
|
||||
|
||||
private string? LabelSave { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
LabelSave = IsNew ? "Aggiungi" : null;
|
||||
|
||||
if (!Id.IsNullOrEmpty())
|
||||
ActivityModel = (await manageData.GetActivity(x => x.ActivityId.Equals(Id))).Last();
|
||||
|
||||
if (IsNew)
|
||||
{
|
||||
ActivityModel.EstimatedTime = DateTime.Today.Add(TimeSpan.FromHours(DateTime.Now.Hour));
|
||||
ActivityModel.EstimatedEndtime = DateTime.Today.Add(TimeSpan.FromHours(DateTime.Now.Hour) + TimeSpan.FromHours(1));
|
||||
}
|
||||
|
||||
OriginalModel = ActivityModel.Clone();
|
||||
}
|
||||
|
||||
private async Task HandleValidSubmit()
|
||||
{
|
||||
// Salva su database (qui simulato)
|
||||
await Task.Delay(200);
|
||||
NavigationManager.NavigateTo("/attivita");
|
||||
}
|
||||
|
||||
private void Annulla()
|
||||
{
|
||||
NavigationManager.NavigateTo("/attivita");
|
||||
}
|
||||
|
||||
private void OnAfterChangeValue()
|
||||
{
|
||||
if (OriginalModel.Equals(ActivityModel))
|
||||
LabelSave = "Aggiorna";
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task CloseDatePicker()
|
||||
{
|
||||
await Task.Delay(150);
|
||||
|
||||
_selectEstimatedTime = false;
|
||||
_selectEstimatedEndTime = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
50
Template.Shared/Components/Pages/ActivityForm.razor.css
Normal file
50
Template.Shared/Components/Pages/ActivityForm.razor.css
Normal file
@@ -0,0 +1,50 @@
|
||||
.input-card {
|
||||
width: 100%;
|
||||
background: var(--mud-palette-background-gray);
|
||||
border-radius: 9px;
|
||||
padding: .5rem 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.input-card ::deep > .divider { margin: 0 !important; }
|
||||
|
||||
.form-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
min-height: 35px;
|
||||
}
|
||||
|
||||
.form-container > span {
|
||||
font-weight: 600;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.dateTime-picker {
|
||||
display: flex;
|
||||
gap: .3rem;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/*Custom mudBlazor*/
|
||||
|
||||
.form-container ::deep .mud-input.mud-input-underline:before { border-bottom: none !important; }
|
||||
|
||||
.form-container ::deep .mud-input.mud-input-underline:after { border-bottom: none !important; }
|
||||
|
||||
.form-container.text-align-end ::deep .mud-input-slot { text-align: end; }
|
||||
|
||||
.input-card ::deep .mud-input.mud-input-underline:before { border-bottom: none !important; }
|
||||
|
||||
.input-card ::deep .mud-input.mud-input-underline:after { border-bottom: none !important; }
|
||||
|
||||
.form-container ::deep .customIcon-select .mud-icon-root.mud-svg-icon {
|
||||
rotate: 90deg !important;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.input-card ::deep .mud-input {
|
||||
width: 100%;
|
||||
font-weight: 500;
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
@@ -1,32 +1,151 @@
|
||||
.activity-filter { margin-top: .2rem; }
|
||||
.arrow-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--mud-palette-primary);
|
||||
font-size: 1.4rem;
|
||||
padding: 0 0.5rem;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
margin-top: .2rem;
|
||||
.arrow-btn:active { color: #2a27b2; }
|
||||
|
||||
.calendar {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.week-slider {
|
||||
width: 100%;
|
||||
transition: all 0.4s ease;
|
||||
transform-origin: center center;
|
||||
transform: scaleY(1);
|
||||
opacity: 1;
|
||||
touch-action: pan-x;
|
||||
user-select: none;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.week-slider:not(.expanded) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 0.6rem;
|
||||
padding: 1rem 0.3rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
.week-slider.expanded {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 0.4rem;
|
||||
padding: 1rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.week-slider.expand-animation { animation: expandFromCenter 0.3s ease forwards; }
|
||||
|
||||
.week-slider.collapse-animation { animation: collapseToCenter 0.3s ease forwards; }
|
||||
|
||||
@keyframes expandFromCenter {
|
||||
from {
|
||||
transform: scaleY(0.6);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scaleY(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes collapseToCenter {
|
||||
from {
|
||||
transform: scaleY(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scaleY(0.6);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.week-day {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.date-controller {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 60px;
|
||||
flex: 1 1 0;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.content ::deep > .custom-mudButtonGroup {
|
||||
width: 100%;
|
||||
.week-day > div:first-child {
|
||||
font-size: 0.8rem;
|
||||
color: var(--mud-palette-primary);
|
||||
margin-bottom: 0.2rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content ::deep > .custom-mudButtonGroup .mud-button-root {
|
||||
border-radius: 12px;
|
||||
padding: .2rem 1.5rem;
|
||||
text-transform: none !important;
|
||||
font-size: .985rem;
|
||||
border: 1px solid var(--mud-palette-gray-light);
|
||||
.day {
|
||||
background: var(--mud-palette-surface);
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s ease, transform 0.2s ease;
|
||||
font-size: 0.95rem;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.content ::deep > .custom-mudButtonGroup .custom-button-active {
|
||||
background-color: hsl(from var(--mud-palette-primary) h s 95%);
|
||||
.day:hover { transform: scale(1.08); }
|
||||
|
||||
.week-slider:not(.expanded) .day {
|
||||
padding: 0;
|
||||
min-width: 38px;
|
||||
min-height: 38px;
|
||||
max-width: 48px;
|
||||
max-height: 48px;
|
||||
}
|
||||
|
||||
.day.selected {
|
||||
background: var(--mud-palette-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.appointments {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
overflow-y: auto;
|
||||
flex-direction: column;
|
||||
height: 70vh;
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.appointments::-webkit-scrollbar { display: none; }
|
||||
|
||||
.appointment {
|
||||
background: var(--mud-palette-surface);
|
||||
border-radius: 8px;
|
||||
padding: 0.8rem;
|
||||
margin-bottom: 0.5rem;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.toggle-month {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--mud-palette-primary);
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -2,27 +2,46 @@
|
||||
@page "/settings/{BackTo}"
|
||||
@using Template.Shared.Components.Layout
|
||||
|
||||
<HeaderLayout BackTo="@BackTo" ShowNotifications="false" Back="true" Title="Impostazioni" />
|
||||
<HeaderLayout BackTo="@BackTo" ShowNotifications="false" Back="true" Title="Impostazioni"/>
|
||||
|
||||
<div class="content">
|
||||
<MudButton Class="user-button"
|
||||
<MudButton Class="button-settings"
|
||||
FullWidth="true"
|
||||
Size="Size.Medium"
|
||||
StartIcon="@Icons.Material.Outlined.Sync"
|
||||
OnClick="UpdateDb"
|
||||
Variant="Variant.Outlined">Sincronizza</MudButton>
|
||||
Size="Size.Medium"
|
||||
OnClick="() => UpdateDb(true)"
|
||||
Variant="Variant.Outlined">
|
||||
Sincronizza
|
||||
</MudButton>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<MudButton Class="button-settings"
|
||||
FullWidth="true"
|
||||
StartIcon="@Icons.Material.Outlined.Sync"
|
||||
Size="Size.Medium"
|
||||
OnClick="() => UpdateDb()"
|
||||
Variant="Variant.Outlined">
|
||||
Ripristina dati
|
||||
</MudButton>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string BackTo { get; set; } = "";
|
||||
|
||||
private void UpdateDb()
|
||||
private void UpdateDb(bool withData = false)
|
||||
{
|
||||
var absoluteUri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);
|
||||
var pathAndQuery = absoluteUri.Segments.Length > 1 ? absoluteUri.PathAndQuery : null;
|
||||
|
||||
var path = pathAndQuery == null ? $"/sync/{DateTime.Today:yyyy-MM-dd}" : $"/sync/{DateTime.Today:yyyy-MM-dd}?path=" + System.Web.HttpUtility.UrlEncode(pathAndQuery);
|
||||
string path;
|
||||
|
||||
NavigationManager.NavigateTo(path);
|
||||
if (withData)
|
||||
path = pathAndQuery == null ? $"/sync/{DateTime.Today:yyyy-MM-dd}" : $"/sync/{DateTime.Today:yyyy-MM-dd}?path=" + System.Web.HttpUtility.UrlEncode(pathAndQuery);
|
||||
else
|
||||
path = pathAndQuery == null ? "/sync" : "/sync?path=" + System.Web.HttpUtility.UrlEncode(pathAndQuery);
|
||||
|
||||
NavigationManager.NavigateTo(path, replace: true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
@using Template.Shared.Components.Layout.Spinner
|
||||
@using Template.Shared.Core.Interface
|
||||
@inject ISyncDbService syncDb
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<SyncSpinner Elements="@Elements"/>
|
||||
|
||||
@@ -11,27 +12,55 @@
|
||||
|
||||
private Dictionary<string, bool> Elements { get; set; } = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
private bool _hasStarted = false;
|
||||
private int _completedCount = 0;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Elements.Add("Attività", false);
|
||||
Elements.Add("Clienti", false);
|
||||
Elements.Add("Commesse", false);
|
||||
StateHasChanged();
|
||||
Elements["Attività"] = false;
|
||||
Elements["Commesse"] = false;
|
||||
Elements["Clienti"] = false;
|
||||
Elements["Prospect"] = false;
|
||||
}
|
||||
|
||||
await Task.WhenAll(SetActivity(), SetClienti(), SetCommesse());
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender && !_hasStarted)
|
||||
{
|
||||
_hasStarted = true;
|
||||
|
||||
LocalStorage.Set("last-sync", DateTime.Now);
|
||||
if (DateFilter is null)
|
||||
{
|
||||
await manageData.ClearDb();
|
||||
}
|
||||
|
||||
var pathQuery = System.Web.HttpUtility.ParseQueryString(new UriBuilder(NavigationManager.Uri).Query);
|
||||
var originalPath = pathQuery["path"] ?? null;
|
||||
var path = originalPath ?? "/Calendar";
|
||||
|
||||
NavigationManager.NavigateTo(path);
|
||||
await Task.WhenAll(RunAndTrack(SetActivity), RunAndTrack(SetClienti), RunAndTrack(SetProspect), RunAndTrack(SetCommesse));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunAndTrack(Func<Task> func)
|
||||
{
|
||||
await func();
|
||||
|
||||
_completedCount++;
|
||||
if (_completedCount == Elements.Count)
|
||||
{
|
||||
LocalStorage.Set("last-sync", DateTime.Now);
|
||||
|
||||
var pathQuery = System.Web.HttpUtility.ParseQueryString(new UriBuilder(NavigationManager.Uri).Query);
|
||||
var originalPath = pathQuery["path"] ?? null;
|
||||
var path = originalPath ?? "/Calendar";
|
||||
|
||||
NavigationManager.NavigateTo(path, replace: true);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetActivity()
|
||||
{
|
||||
await syncDb.GetAndSaveActivity(DateFilter);
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await syncDb.GetAndSaveActivity(DateFilter);
|
||||
});
|
||||
|
||||
Elements["Attività"] = true;
|
||||
StateHasChanged();
|
||||
@@ -39,16 +68,32 @@
|
||||
|
||||
private async Task SetClienti()
|
||||
{
|
||||
await syncDb.GetAndSaveClienti(DateFilter);
|
||||
await syncDb.GetAndSaveProspect(DateFilter);
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await syncDb.GetAndSaveClienti(DateFilter);
|
||||
});
|
||||
|
||||
Elements["Clienti"] = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task SetProspect()
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await syncDb.GetAndSaveProspect(DateFilter);
|
||||
});
|
||||
|
||||
Elements["Prospect"] = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task SetCommesse()
|
||||
{
|
||||
await syncDb.GetAndSaveCommesse(DateFilter);
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
await syncDb.GetAndSaveCommesse(DateFilter);
|
||||
});
|
||||
|
||||
Elements["Commesse"] = true;
|
||||
StateHasChanged();
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
@using ConSegna.Shared.Core.Helpers
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Interface
|
||||
@using Template.Shared.Components.Layout.Spinner
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<div class="calendar">
|
||||
@if (!Activities.IsNullOrEmpty())
|
||||
@if (Load)
|
||||
{
|
||||
@foreach (var activity in Activities!)
|
||||
{
|
||||
<ActivityCard Activity="activity"/>
|
||||
}
|
||||
<SpinnerLayout FullScreen="false" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<NoDataAvailable Text="Nessuna attività trovata" ImageSource="_content/Template.Shared/images/undraw_file-search_cbur.svg"/>
|
||||
@if (!Activities.IsNullOrEmpty())
|
||||
{
|
||||
@foreach (var activity in Activities!)
|
||||
{
|
||||
<ActivityCard Activity="activity"/>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<NoDataAvailable Text="Nessuna attività trovata" ImageSource="_content/Template.Shared/images/undraw_file-search_cbur.svg"/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -23,7 +30,8 @@
|
||||
[Parameter] public required DateTime? Date { get; set; }
|
||||
[Parameter] public EventCallback<DateTime?> DateChanged { get; set; }
|
||||
|
||||
private List<ActivityDTO>? Activities { get; set; } = null;
|
||||
private List<ActivityDTO>? Activities { get; set; }
|
||||
private bool Load { get; set; } = true;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
@@ -40,9 +48,13 @@
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
Load = true;
|
||||
StateHasChanged();
|
||||
|
||||
await Task.Delay(500);
|
||||
var refreshActivity = await RefreshActivity();
|
||||
Activities = refreshActivity;
|
||||
Load = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
.calendar::-webkit-scrollbar { display: none; }
|
||||
|
||||
|
||||
.calendar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
@@ -1,42 +1,67 @@
|
||||
<div class="calendar">
|
||||
@foreach (var nomeGiorno in _giorniSettimana)
|
||||
{
|
||||
<div class="calendar-header">@nomeGiorno</div>
|
||||
}
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Interface
|
||||
@inject IManageDataService manageData
|
||||
|
||||
@for (var i = 0; i < StartDays; i++)
|
||||
{
|
||||
<div class="calendar-day disabled @(i == 0 ? "radiusTopLeft" : "")"></div>
|
||||
}
|
||||
<div class="calendar-activity">
|
||||
<div class="calendar">
|
||||
@foreach (var nomeGiorno in _giorniSettimana)
|
||||
{
|
||||
<div class="calendar-header">@nomeGiorno</div>
|
||||
}
|
||||
|
||||
@for (var day = 1; day <= DaysInMonth; day++)
|
||||
{
|
||||
var currentDate = new DateTime(Date.Year, Date.Month, day);
|
||||
var events = GetEventsForDay(currentDate);
|
||||
var isToday = currentDate == DateTime.Today;
|
||||
@for (var i = 0; i < StartDays; i++)
|
||||
{
|
||||
<div class="calendar-day disabled @(i == 0 ? "radiusTopLeft" : "")"></div>
|
||||
}
|
||||
|
||||
var topRight = StartDays == 0 ? 7 : 7 - StartDays;
|
||||
var bottomLeft = DaysInMonth - (6 - EndDays);
|
||||
@for (var day = 1; day <= DaysInMonth; day++)
|
||||
{
|
||||
var currentDate = new DateTime(Date.Year, Date.Month, day);
|
||||
var events = GetEventsForDay(currentDate);
|
||||
var daySelected = SelectedDate == currentDate;
|
||||
var isToday = currentDate == DateTime.Today;
|
||||
|
||||
<div class="calendar-day @(isToday ? "today" : "")
|
||||
var topRight = StartDays == 0 ? 7 : 7 - StartDays;
|
||||
var bottomLeft = DaysInMonth - (6 - EndDays);
|
||||
|
||||
var categoryActivityCount = events.Select(x => x.Category).Distinct().ToList();
|
||||
|
||||
<div @onclick="() => SelectDay(currentDate)" class="calendar-day @(isToday ? "today" : daySelected ? "selectedDay" : "")
|
||||
@(StartDays == 0 && day == 1 ? "radiusTopLeft" : "")
|
||||
@(EndDays == 0 && day == DaysInMonth ? "radiusBottomRight" : "")
|
||||
@(bottomLeft == day ? "radiusBottomLeft" : "")
|
||||
@(topRight == day ? "radiusTopRight" : "")">
|
||||
<div class="calendar-day-wrapper">
|
||||
<span class="titleDay">@day</span>
|
||||
@if (events.Any())
|
||||
{
|
||||
<div class="event-dot"></div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@for (var i = 0; i < EndDays; i++)
|
||||
{
|
||||
<div class="calendar-day disabled @(i + 1 == EndDays ? "radiusBottomRight" : "")"></div>
|
||||
}
|
||||
<div class="calendar-day-wrapper">
|
||||
<span class="titleDay">@day</span>
|
||||
@if (events.Any())
|
||||
{
|
||||
<div class="event-dot-container">
|
||||
@foreach (var activityCategory in categoryActivityCount)
|
||||
{
|
||||
<div class="event-dot @activityCategory.ConvertToHumanReadable()"></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@for (var i = 0; i < EndDays; i++)
|
||||
{
|
||||
<div class="calendar-day disabled @(i + 1 == EndDays ? "radiusBottomRight" : "")"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="activityContainer">
|
||||
@if (!FilteredActivityList.IsNullOrEmpty())
|
||||
{
|
||||
@foreach (var activity in FilteredActivityList!)
|
||||
{
|
||||
<ActivityCard Activity="activity"/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code
|
||||
@@ -44,7 +69,9 @@
|
||||
[Parameter] public required DateTime Date { get; set; }
|
||||
[Parameter] public EventCallback<DateTime> DateChanged { get; set; }
|
||||
|
||||
private List<CalendarEvent> Events { get; set; }
|
||||
private List<ActivityDTO> ActivityList { get; set; } = [];
|
||||
private List<ActivityDTO> FilteredActivityList { get; set; } = [];
|
||||
private DateTime SelectedDate { get; set; } = DateTime.Today;
|
||||
|
||||
private int DaysInMonth { get; set; }
|
||||
private int StartDays { get; set; }
|
||||
@@ -52,17 +79,17 @@
|
||||
|
||||
readonly string[] _giorniSettimana = ["Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"];
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
ChangeMonth();
|
||||
await ChangeMonth();
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
ChangeMonth();
|
||||
await ChangeMonth();
|
||||
}
|
||||
|
||||
private void ChangeMonth()
|
||||
private async Task ChangeMonth()
|
||||
{
|
||||
var firstDay = Date;
|
||||
DaysInMonth = DateTime.DaysInMonth(firstDay.Year, firstDay.Month);
|
||||
@@ -74,23 +101,50 @@
|
||||
var totalCell = tempTotalCell * 7;
|
||||
EndDays = totalCell - (DaysInMonth + StartDays);
|
||||
|
||||
Events =
|
||||
[
|
||||
new CalendarEvent { Date = DateTime.Today, Title = "Meeting", Time = "10:00" },
|
||||
new CalendarEvent { Date = DateTime.Today.AddDays(2), Title = "Dentista", Time = "15:30" },
|
||||
new CalendarEvent { Date = DateTime.Today.AddDays(5), Title = "Scadenza", Time = "Tutto il giorno" }
|
||||
];
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private List<CalendarEvent> GetEventsForDay(DateTime day)
|
||||
private async Task LoadData()
|
||||
{
|
||||
return Events.Where(e => e.Date.Date == day.Date).ToList();
|
||||
// Load = true;
|
||||
// StateHasChanged();
|
||||
|
||||
await Task.Delay(500);
|
||||
var refreshActivity = await RefreshActivity();
|
||||
ActivityList = refreshActivity;
|
||||
// Load = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public class CalendarEvent
|
||||
private async Task<List<ActivityDTO>> RefreshActivity()
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public string Title { get; set; } = "";
|
||||
public string Time { get; set; } = "";
|
||||
var startDate = Date;
|
||||
var endDate = Date.AddDays(DateTime.DaysInMonth(startDate.Year, startDate.Month) - 1);
|
||||
|
||||
var dateRange = new DateRange(Date, endDate);
|
||||
|
||||
var activityDto = await Task.Run(async () =>
|
||||
{
|
||||
return (await manageData.GetActivity(x =>
|
||||
(x.EffectiveDate == null && x.EstimatedDate >= dateRange.Start && x.EstimatedDate <= dateRange.End) ||
|
||||
(x.EffectiveDate >= dateRange.Start && x.EffectiveDate <= dateRange.End)
|
||||
))
|
||||
.OrderBy(x => x.EffectiveDate ?? x.EstimatedDate)
|
||||
.ToList();
|
||||
});
|
||||
|
||||
return activityDto;
|
||||
}
|
||||
|
||||
private List<ActivityDTO> GetEventsForDay(DateTime day)
|
||||
{
|
||||
return ActivityList.IsNullOrEmpty() ? [] : ActivityList.Where(x => (x.EffectiveDate ?? x.EstimatedDate) == day.Date).ToList();
|
||||
}
|
||||
|
||||
private void SelectDay(DateTime currentDate)
|
||||
{
|
||||
SelectedDate = currentDate;
|
||||
StateHasChanged();
|
||||
FilteredActivityList = GetEventsForDay(currentDate);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
.calendar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
/*border: 1px solid #ccc;*/
|
||||
}
|
||||
|
||||
.calendar-header, .calendar-day {
|
||||
@@ -31,6 +30,11 @@
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.selectedDay > .calendar-day-wrapper > .titleDay {
|
||||
border: 1px solid var(--mud-palette-primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.calendar-day-wrapper > .titleDay {
|
||||
padding: 6px;
|
||||
border-radius: 50%;
|
||||
@@ -38,15 +42,28 @@
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.event-dot-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .2rem;
|
||||
}
|
||||
|
||||
.event-dot {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--mud-palette-secondary);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.event-dot.memo { background-color: var(--mud-palette-info-darken); }
|
||||
|
||||
.event-dot.interna { background-color: var(--mud-palette-success-darken); }
|
||||
|
||||
.event-dot.commessa { background-color: var(--mud-palette-warning); }
|
||||
|
||||
.calendar-day:hover .event-popup { display: block; }
|
||||
|
||||
.calendar-day-wrapper {
|
||||
@@ -61,4 +78,24 @@
|
||||
|
||||
.radiusBottomLeft { border-bottom-left-radius: 12px; }
|
||||
|
||||
.radiusBottomRight { border-bottom-right-radius: 12px; }
|
||||
.radiusBottomRight { border-bottom-right-radius: 12px; }
|
||||
|
||||
.activityContainer { margin-top: 1rem; }
|
||||
|
||||
.calendar-activity {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.calendar-activity::-webkit-scrollbar { display: none; }
|
||||
|
||||
.calendar-activity {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
@using ConSegna.Shared.Core.Helpers
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Interface
|
||||
@using Template.Shared.Components.Layout.Spinner
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<div class="calendar">
|
||||
@@ -8,26 +8,33 @@
|
||||
DateTime? currentDate = null;
|
||||
}
|
||||
|
||||
@if (!Activities.IsNullOrEmpty())
|
||||
@if (Load)
|
||||
{
|
||||
foreach (var activity in Activities!)
|
||||
{
|
||||
var dateToShow = activity.EffectiveDate ?? activity.EstimatedDate;
|
||||
|
||||
if (currentDate != dateToShow?.Date)
|
||||
{
|
||||
currentDate = dateToShow?.Date;
|
||||
<div class="week-info">
|
||||
<span>@($"{currentDate:D}")</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<ActivityCard Activity="activity"/>
|
||||
}
|
||||
<SpinnerLayout FullScreen="false"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<NoDataAvailable Text="Nessuna attività trovata" ImageSource="_content/Template.Shared/images/undraw_file-search_cbur.svg"/>
|
||||
@if (!Activities.IsNullOrEmpty())
|
||||
{
|
||||
foreach (var activity in Activities!)
|
||||
{
|
||||
var dateToShow = activity.EffectiveDate ?? activity.EstimatedDate;
|
||||
|
||||
if (currentDate != dateToShow?.Date)
|
||||
{
|
||||
currentDate = dateToShow?.Date;
|
||||
<div class="week-info">
|
||||
<span>@($"{currentDate:D}")</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<ActivityCard Activity="activity"/>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<NoDataAvailable Text="Nessuna attività trovata" ImageSource="_content/Template.Shared/images/undraw_file-search_cbur.svg"/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -37,6 +44,7 @@
|
||||
[Parameter] public EventCallback<DateRange> DateChanged { get; set; }
|
||||
|
||||
private List<ActivityDTO>? Activities { get; set; }
|
||||
private bool Load { get; set; } = true;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
@@ -53,9 +61,13 @@
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
Load = true;
|
||||
StateHasChanged();
|
||||
|
||||
await Task.Delay(500);
|
||||
var refreshActivity = await RefreshActivity();
|
||||
Activities = refreshActivity;
|
||||
Load = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -63,7 +75,7 @@
|
||||
{
|
||||
var activityDto = await Task.Run(async () =>
|
||||
{
|
||||
return Activities = (await manageData.GetActivity(x =>
|
||||
return (await manageData.GetActivity(x =>
|
||||
(x.EffectiveDate == null && x.EstimatedDate >= Date.Start && x.EstimatedDate <= Date.End) ||
|
||||
(x.EffectiveDate >= Date.Start && x.EffectiveDate <= Date.End)
|
||||
))
|
||||
|
||||
@@ -1,31 +1,57 @@
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Helpers.Enum
|
||||
|
||||
<div class="activity-card @Activity.Category.ConvertToHumanReadable()">
|
||||
<div class="activity-card @Activity.Category.ConvertToHumanReadable()" @onclick="() => OpenActivityForm(Activity.ActivityId)">
|
||||
<div class="activity-left-section">
|
||||
<div class="activity-hours-section">
|
||||
<span class="activity-hours">
|
||||
@if (Activity.EffectiveTime is null)
|
||||
{
|
||||
@($"{Activity.EstimatedTime:t}")
|
||||
}
|
||||
else
|
||||
{
|
||||
@($"{Activity.EffectiveTime:t}")
|
||||
}
|
||||
</span>
|
||||
@if (Durata != null)
|
||||
{
|
||||
<MudChip T="string" Icon="@IconConstants.Chip.Time" Color="Color.Dark" Size="Size.Small">@($"{Durata.Value.TotalHours:####}h")</MudChip>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="activity-body-section">
|
||||
<MudText Class="activity-title" Typo="Typo.button" HtmlTag="h3">@Activity.Commessa</MudText>
|
||||
<MudText Class="activity-subtitle" Typo="Typo.caption">@Activity.ActivityDescription</MudText>
|
||||
<div class="title-section">
|
||||
<MudText Class="activity-title" Typo="Typo.body1" HtmlTag="h3">
|
||||
@switch (Activity.Category)
|
||||
{
|
||||
case ActivityCategoryEnum.Commessa:
|
||||
@Activity.Commessa
|
||||
break;
|
||||
case ActivityCategoryEnum.Interna:
|
||||
@Activity.Cliente
|
||||
break;
|
||||
case ActivityCategoryEnum.Memo:
|
||||
@Activity.ActivityDescription
|
||||
break;
|
||||
default:
|
||||
@("")
|
||||
break;
|
||||
}
|
||||
</MudText>
|
||||
<div class="activity-hours-section">
|
||||
<span class="activity-hours">
|
||||
@if (Activity.EffectiveTime is null)
|
||||
{
|
||||
@($"{Activity.EstimatedTime:t}")
|
||||
}
|
||||
else
|
||||
{
|
||||
@($"{Activity.EffectiveTime:t}")
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@if (Activity.Category != ActivityCategoryEnum.Memo)
|
||||
{
|
||||
<MudText Class="activity-subtitle" Typo="Typo.body1" HtmlTag="p">@Activity.ActivityDescription</MudText>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="activity-info-section">
|
||||
@if (Durata != null && (Durata.Value.TotalHours > 0 || Durata.Value.Minutes > 0))
|
||||
{
|
||||
var ore = (int)Durata.Value.TotalHours;
|
||||
var minuti = Durata.Value.Minutes;
|
||||
|
||||
<MudChip T="string" Icon="@IconConstants.Chip.Time" Color="Color.Dark" Size="Size.Small">
|
||||
@(ore > 0 ? $"{ore}h{(minuti > 0 ? $" {minuti}m" : "")}" : $"{minuti}m")
|
||||
</MudChip>
|
||||
}
|
||||
@if (Activity.ActivityResultId != null)
|
||||
{
|
||||
<MudChip T="string" Icon="@IconConstants.Chip.Stato" Size="Size.Small" Color="Color.Success">@Activity.ActivityResultId</MudChip>
|
||||
@@ -38,7 +64,6 @@
|
||||
[Parameter] public ActivityDTO Activity { get; set; } = new();
|
||||
|
||||
private TimeSpan? Durata { get; set; }
|
||||
private Color ColorStatus { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
@@ -46,7 +71,15 @@
|
||||
{
|
||||
{ EffectiveTime: not null, EffectiveEndtime: not null } => Activity.EffectiveEndtime.Value - Activity.EffectiveTime.Value,
|
||||
{ EstimatedTime: not null, EstimatedEndtime: not null } => Activity.EstimatedEndtime.Value - Activity.EstimatedTime.Value,
|
||||
_ => Durata
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private void OpenActivityForm(string? activityId)
|
||||
{
|
||||
var url = "/activity";
|
||||
url = !activityId.IsNullOrEmpty() ? $"{url}/{activityId}" : url;
|
||||
|
||||
NavigationManager.NavigateTo(url);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
.activity-card {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: .5rem .7rem;
|
||||
flex-direction: column;
|
||||
padding: .5rem .5rem;
|
||||
border-radius: 12px;
|
||||
line-height: normal;
|
||||
border: 1px solid var(--card-border-color);
|
||||
box-shadow: var(--card-shadow);
|
||||
}
|
||||
|
||||
.activity-card.memo { border-left: 5px solid var(--mud-palette-info-darken); }
|
||||
@@ -20,13 +17,14 @@
|
||||
.activity-left-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.activity-hours-section {
|
||||
width: min-content;
|
||||
.title-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.activity-hours { font-weight: 700; }
|
||||
@@ -34,22 +32,24 @@
|
||||
.activity-hours-section ::deep .mud-chip { margin: 5px 0 0 !important; }
|
||||
|
||||
.activity-body-section {
|
||||
width: fit-content;
|
||||
margin: 0 1rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.activity-body-section ::deep > .activity-title {
|
||||
.title-section ::deep > .activity-title {
|
||||
font-weight: 800 !important;
|
||||
margin: 0 0 .2rem 0 !important;
|
||||
margin: 0 !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.activity-body-section ::deep > .activity-subtitle {
|
||||
font-size: smaller;
|
||||
color: var(--mud-palette-gray-darker);
|
||||
margin: .2rem 0 !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.activity-info-section { width: min-content; }
|
||||
.activity-info-section {
|
||||
width: min-content;
|
||||
display: flex;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
.no-data {
|
||||
position: fixed;
|
||||
top: 35%;
|
||||
margin-top: 2rem;
|
||||
width: calc(100vw - (var(--bs-gutter-x) * .5) * 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,92 @@ namespace Template.Shared.Core.Dto;
|
||||
public class ActivityDTO : StbActivity
|
||||
{
|
||||
public string? Commessa { get; set; }
|
||||
public string? Cliente { get; set; }
|
||||
public ActivityCategoryEnum Category { get; set; }
|
||||
public bool Complete { get; set; }
|
||||
|
||||
private sealed class ActivityDtoEqualityComparer : IEqualityComparer<ActivityDTO>
|
||||
{
|
||||
public bool Equals(ActivityDTO? x, ActivityDTO? y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (x is null) return false;
|
||||
if (y is null) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.ActivityId == y.ActivityId && x.ActivityResultId == y.ActivityResultId && x.ActivityTypeId == y.ActivityTypeId && x.DataInsAct.Equals(y.DataInsAct) && x.ActivityDescription == y.ActivityDescription && x.ParentActivityId == y.ParentActivityId && x.TipoAnag == y.TipoAnag && x.CodAnag == y.CodAnag && x.CodJcom == y.CodJcom && x.CodJfas == y.CodJfas && Nullable.Equals(x.EstimatedDate, y.EstimatedDate) && Nullable.Equals(x.EstimatedTime, y.EstimatedTime) && Nullable.Equals(x.AlarmDate, y.AlarmDate) && Nullable.Equals(x.AlarmTime, y.AlarmTime) && Nullable.Equals(x.EffectiveDate, y.EffectiveDate) && Nullable.Equals(x.EffectiveTime, y.EffectiveTime) && x.ResultDescription == y.ResultDescription && Nullable.Equals(x.EstimatedEnddate, y.EstimatedEnddate) && Nullable.Equals(x.EstimatedEndtime, y.EstimatedEndtime) && Nullable.Equals(x.EffectiveEnddate, y.EffectiveEnddate) && Nullable.Equals(x.EffectiveEndtime, y.EffectiveEndtime) && x.UserCreator == y.UserCreator && x.UserName == y.UserName && Nullable.Equals(x.PercComp, y.PercComp) && Nullable.Equals(x.EstimatedHours, y.EstimatedHours) && x.CodMart == y.CodMart && x.PartitaMag == y.PartitaMag && x.Matricola == y.Matricola && x.Priorita == y.Priorita && Nullable.Equals(x.ActivityPlayCounter, y.ActivityPlayCounter) && x.ActivityEvent == y.ActivityEvent && x.Guarantee == y.Guarantee && x.Note == y.Note && x.Rfid == y.Rfid && x.IdLotto == y.IdLotto && x.PersonaRif == y.PersonaRif && x.HrNum == y.HrNum && x.Gestione == y.Gestione && Nullable.Equals(x.DataOrd, y.DataOrd) && x.NumOrd == y.NumOrd && x.IdStep == y.IdStep && x.IdRiga == y.IdRiga && Nullable.Equals(x.OraInsAct, y.OraInsAct) && x.IndiceGradimento == y.IndiceGradimento && x.NoteGradimento == y.NoteGradimento && x.FlagRisolto == y.FlagRisolto && x.FlagTipologia == y.FlagTipologia && x.OreRapportino == y.OreRapportino && x.UserModifier == y.UserModifier && Nullable.Equals(x.OraModAct, y.OraModAct) && Nullable.Equals(x.OraViewAct, y.OraViewAct) && x.CodVdes == y.CodVdes && x.CodCmac == y.CodCmac && x.WrikeId == y.WrikeId && x.CodMgrp == y.CodMgrp && x.PlanId == y.PlanId && x.Commessa == y.Commessa && x.Cliente == y.Cliente && x.Category == y.Category && x.Complete == y.Complete;
|
||||
}
|
||||
|
||||
public int GetHashCode(ActivityDTO obj)
|
||||
{
|
||||
var hashCode = new HashCode();
|
||||
hashCode.Add(obj.ActivityId);
|
||||
hashCode.Add(obj.ActivityResultId);
|
||||
hashCode.Add(obj.ActivityTypeId);
|
||||
hashCode.Add(obj.DataInsAct);
|
||||
hashCode.Add(obj.ActivityDescription);
|
||||
hashCode.Add(obj.ParentActivityId);
|
||||
hashCode.Add(obj.TipoAnag);
|
||||
hashCode.Add(obj.CodAnag);
|
||||
hashCode.Add(obj.CodJcom);
|
||||
hashCode.Add(obj.CodJfas);
|
||||
hashCode.Add(obj.EstimatedDate);
|
||||
hashCode.Add(obj.EstimatedTime);
|
||||
hashCode.Add(obj.AlarmDate);
|
||||
hashCode.Add(obj.AlarmTime);
|
||||
hashCode.Add(obj.EffectiveDate);
|
||||
hashCode.Add(obj.EffectiveTime);
|
||||
hashCode.Add(obj.ResultDescription);
|
||||
hashCode.Add(obj.EstimatedEnddate);
|
||||
hashCode.Add(obj.EstimatedEndtime);
|
||||
hashCode.Add(obj.EffectiveEnddate);
|
||||
hashCode.Add(obj.EffectiveEndtime);
|
||||
hashCode.Add(obj.UserCreator);
|
||||
hashCode.Add(obj.UserName);
|
||||
hashCode.Add(obj.PercComp);
|
||||
hashCode.Add(obj.EstimatedHours);
|
||||
hashCode.Add(obj.CodMart);
|
||||
hashCode.Add(obj.PartitaMag);
|
||||
hashCode.Add(obj.Matricola);
|
||||
hashCode.Add(obj.Priorita);
|
||||
hashCode.Add(obj.ActivityPlayCounter);
|
||||
hashCode.Add(obj.ActivityEvent);
|
||||
hashCode.Add(obj.Guarantee);
|
||||
hashCode.Add(obj.Note);
|
||||
hashCode.Add(obj.Rfid);
|
||||
hashCode.Add(obj.IdLotto);
|
||||
hashCode.Add(obj.PersonaRif);
|
||||
hashCode.Add(obj.HrNum);
|
||||
hashCode.Add(obj.Gestione);
|
||||
hashCode.Add(obj.DataOrd);
|
||||
hashCode.Add(obj.NumOrd);
|
||||
hashCode.Add(obj.IdStep);
|
||||
hashCode.Add(obj.IdRiga);
|
||||
hashCode.Add(obj.OraInsAct);
|
||||
hashCode.Add(obj.IndiceGradimento);
|
||||
hashCode.Add(obj.NoteGradimento);
|
||||
hashCode.Add(obj.FlagRisolto);
|
||||
hashCode.Add(obj.FlagTipologia);
|
||||
hashCode.Add(obj.OreRapportino);
|
||||
hashCode.Add(obj.UserModifier);
|
||||
hashCode.Add(obj.OraModAct);
|
||||
hashCode.Add(obj.OraViewAct);
|
||||
hashCode.Add(obj.CodVdes);
|
||||
hashCode.Add(obj.CodCmac);
|
||||
hashCode.Add(obj.WrikeId);
|
||||
hashCode.Add(obj.CodMgrp);
|
||||
hashCode.Add(obj.PlanId);
|
||||
hashCode.Add(obj.Commessa);
|
||||
hashCode.Add(obj.Cliente);
|
||||
hashCode.Add((int)obj.Category);
|
||||
hashCode.Add(obj.Complete);
|
||||
return hashCode.ToHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<ActivityDTO> ActivityDtoComparer { get; } = new ActivityDtoEqualityComparer();
|
||||
|
||||
public ActivityDTO Clone()
|
||||
{
|
||||
return (ActivityDTO)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
6
Template.Shared/Core/Dto/ActivityResultDTO.cs
Normal file
6
Template.Shared/Core/Dto/ActivityResultDTO.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Template.Shared.Core.Dto;
|
||||
|
||||
public class ActivityResultDTO
|
||||
{
|
||||
public string ActivityResultId { get; set; }
|
||||
}
|
||||
@@ -1,12 +1,22 @@
|
||||
using Template.Shared.Core.Entity;
|
||||
using System.Text.Json.Serialization;
|
||||
using Template.Shared.Core.Entity;
|
||||
|
||||
namespace Template.Shared.Core.Dto;
|
||||
|
||||
public class TaskSyncResponseDTO
|
||||
{
|
||||
[JsonPropertyName("anagClie")]
|
||||
public List<AnagClie>? AnagClie { get; set; }
|
||||
|
||||
[JsonPropertyName("vtbDest")]
|
||||
public List<VtbDest>? VtbDest { get; set; }
|
||||
|
||||
[JsonPropertyName("vtbCliePersRif")]
|
||||
public List<VtbCliePersRif>? VtbCliePersRif { get; set; }
|
||||
|
||||
[JsonPropertyName("ptbPros")]
|
||||
public List<PtbPros>? PtbPros { get; set; }
|
||||
|
||||
[JsonPropertyName("ptbProsRif")]
|
||||
public List<PtbProsRif>? PtbProsRif { get; set; }
|
||||
}
|
||||
@@ -6,10 +6,10 @@ namespace Template.Shared.Core.Entity;
|
||||
[Table("ptb_pros_rif")]
|
||||
public class PtbProsRif
|
||||
{
|
||||
[PrimaryKey, Column("cod_ppro"), JsonPropertyName("codPpro")]
|
||||
[Column("cod_ppro"), JsonPropertyName("codPpro"), Indexed(Name = "PtbProsRifPK", Order = 1, Unique = true)]
|
||||
public string CodPpro { get; set; }
|
||||
|
||||
[PrimaryKey, Column("id_pers_rif"), JsonPropertyName("idPersRif")]
|
||||
[Column("id_pers_rif"), JsonPropertyName("idPersRif"), Indexed(Name = "PtbProsRifPK", Order = 2, Unique = true)]
|
||||
public int IdPersRif { get; set; }
|
||||
|
||||
[Column("persona_rif"), JsonPropertyName("personaRif")]
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace Template.Shared.Core.Entity;
|
||||
[Table("vtb_clie_pers_rif")]
|
||||
public class VtbCliePersRif
|
||||
{
|
||||
[PrimaryKey, Column("id_pers_rif"), JsonPropertyName("idPersRif")]
|
||||
[Column("id_pers_rif"), JsonPropertyName("idPersRif"), Indexed(Name = "VtbCliePersRifPK", Order = 1, Unique = true)]
|
||||
public int IdPersRif { get; set; }
|
||||
|
||||
[PrimaryKey, Column("cod_anag"), JsonPropertyName("codAnag")]
|
||||
[Column("cod_anag"), JsonPropertyName("codAnag"), Indexed(Name = "VtbCliePersRifPK", Order = 2, Unique = true)]
|
||||
public string CodAnag { get; set; }
|
||||
|
||||
[Column("persona_rif"), JsonPropertyName("personaRif")]
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace Template.Shared.Core.Entity;
|
||||
[Table("vtb_dest")]
|
||||
public class VtbDest
|
||||
{
|
||||
[PrimaryKey, Column("cod_anag"), JsonPropertyName("codAnag")]
|
||||
[Column("cod_anag"), JsonPropertyName("codAnag"), Indexed(Name = "VtbDestPK", Order = 1, Unique = true)]
|
||||
public string CodAnag { get; set; }
|
||||
|
||||
[PrimaryKey, Column("cod_vdes"), JsonPropertyName("codVdes")]
|
||||
[Column("cod_vdes"), JsonPropertyName("codVdes"), Indexed(Name = "VtbDestPK", Order = 2, Unique = true)]
|
||||
public string CodVdes { get; set; }
|
||||
|
||||
[Column("destinatario"), JsonPropertyName("destinatario")]
|
||||
|
||||
@@ -9,7 +9,7 @@ public static class ActivityCategoryHelper
|
||||
return activityType switch
|
||||
{
|
||||
ActivityCategoryEnum.Memo => "memo",
|
||||
ActivityCategoryEnum.Interna => "inerna",
|
||||
ActivityCategoryEnum.Interna => "interna",
|
||||
ActivityCategoryEnum.Commessa => "commessa",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(activityType), activityType, null)
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace ConSegna.Shared.Core.Helpers;
|
||||
namespace Template.Shared.Core.Helpers;
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
|
||||
@@ -15,4 +15,6 @@ public interface IManageDataService
|
||||
Task<List<VtbDest>> GetVtbDest(Expression<Func<VtbDest, bool>>? whereCond = null);
|
||||
|
||||
Task<List<ActivityDTO>> GetActivity(Expression<Func<StbActivity, bool>>? whereCond = null);
|
||||
|
||||
Task ClearDb();
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class IntegryApiService(IIntegryApiRestClient integryApiRestClient, IUser
|
||||
{
|
||||
var queryParams = new Dictionary<string, object> { { "dateFilter", dateFilter ?? "2020-01-01" } };
|
||||
|
||||
return integryApiRestClient.AuthorizedGet<List<StbActivity>?>("task/getActivity", queryParams);
|
||||
return integryApiRestClient.AuthorizedGet<List<StbActivity>?>("getActivityCrm", queryParams);
|
||||
}
|
||||
|
||||
public Task<List<JtbComt>?> GetAllCommesse(string? dateFilter)
|
||||
@@ -25,7 +25,7 @@ public class IntegryApiService(IIntegryApiRestClient integryApiRestClient, IUser
|
||||
queryParams.Add("dateFilter", dateFilter);
|
||||
}
|
||||
|
||||
return integryApiRestClient.AuthorizedGet<List<JtbComt>?>("task/getCommesse", queryParams);
|
||||
return integryApiRestClient.AuthorizedGet<List<JtbComt>?>("getCommesseCrm", queryParams);
|
||||
}
|
||||
|
||||
public Task<TaskSyncResponseDTO> GetAnagClie(string? dateFilter)
|
||||
@@ -37,7 +37,7 @@ public class IntegryApiService(IIntegryApiRestClient integryApiRestClient, IUser
|
||||
queryParams.Add("dateFilter", dateFilter);
|
||||
}
|
||||
|
||||
return integryApiRestClient.AuthorizedGet<TaskSyncResponseDTO>("task/getAnagClie", queryParams)!;
|
||||
return integryApiRestClient.AuthorizedGet<TaskSyncResponseDTO>("getAnagClieCrm", queryParams)!;
|
||||
}
|
||||
|
||||
public Task<TaskSyncResponseDTO> GetProspect(string? dateFilter)
|
||||
@@ -49,6 +49,6 @@ public class IntegryApiService(IIntegryApiRestClient integryApiRestClient, IUser
|
||||
queryParams.Add("dateFilter", dateFilter);
|
||||
}
|
||||
|
||||
return integryApiRestClient.AuthorizedGet<TaskSyncResponseDTO>("task/getProspect", queryParams)!;
|
||||
return integryApiRestClient.AuthorizedGet<TaskSyncResponseDTO>("getProspectCrm", queryParams)!;
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,12 @@ public static class UtilityString
|
||||
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(word => char.ToUpper(word[0])));
|
||||
}
|
||||
|
||||
public static string FirstCharToUpper(this string input) =>
|
||||
input switch
|
||||
{
|
||||
null => throw new ArgumentNullException(nameof(input)),
|
||||
"" => throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)),
|
||||
_ => input[0].ToString().ToUpper() + input.Substring(1)
|
||||
};
|
||||
}
|
||||
@@ -1,30 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="IntegryApiClient.Core" Version="1.1.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.4" />
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.9.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.4" />
|
||||
<PackageReference Include="MudBlazor" Version="8.6.0" />
|
||||
<PackageReference Include="MudBlazor.ThemeManager" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="14.0.0"/>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||
<PackageReference Include="IntegryApiClient.Core" Version="1.1.4"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.5"/>
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172"/>
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.11.0"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.5"/>
|
||||
<PackageReference Include="MudBlazor" Version="8.6.0"/>
|
||||
<PackageReference Include="MudBlazor.ThemeManager" Version="3.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\css\lineicons\" />
|
||||
<Folder Include="wwwroot\js\bootstrap\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\css\lineicons\"/>
|
||||
<Folder Include="wwwroot\js\bootstrap\"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -14,6 +14,7 @@
|
||||
@using Template.Shared.Components.SingleElements.Card
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Template.Shared.Core.Utility
|
||||
@using static InteractiveRenderSettings
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@@ -107,7 +107,7 @@ h1:focus { outline: none; }
|
||||
.divider {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 1px solid var(--card-border-color);
|
||||
border: .05rem solid var(--card-border-color);
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
|
||||
41
Template.Shared/wwwroot/js/calendar.js
Normal file
41
Template.Shared/wwwroot/js/calendar.js
Normal file
@@ -0,0 +1,41 @@
|
||||
window.calendarSwipe = {
|
||||
register: function (element, dotnetHelper) {
|
||||
let startX = 0;
|
||||
let endX = 0;
|
||||
|
||||
element.addEventListener('touchstart', (e) => {
|
||||
if (e.touches.length === 1) {
|
||||
startX = e.touches[0].clientX;
|
||||
}
|
||||
});
|
||||
|
||||
element.addEventListener('touchend', (e) => {
|
||||
if (e.changedTouches.length === 1) {
|
||||
endX = e.changedTouches[0].clientX;
|
||||
handle();
|
||||
}
|
||||
});
|
||||
|
||||
// Per desktop: mouse drag
|
||||
let mouseDown = false;
|
||||
element.addEventListener('mousedown', (e) => {
|
||||
if (e.button !== 0) return; // solo left mouse
|
||||
mouseDown = true;
|
||||
startX = e.clientX;
|
||||
});
|
||||
element.addEventListener('mouseup', (e) => {
|
||||
if (!mouseDown) return;
|
||||
mouseDown = false;
|
||||
endX = e.clientX;
|
||||
handle();
|
||||
});
|
||||
|
||||
function handle() {
|
||||
let diff = endX - startX;
|
||||
if (Math.abs(diff) > 40) {
|
||||
if (diff < 0) dotnetHelper.invokeMethodAsync('OnSwipeLeft');
|
||||
else dotnetHelper.invokeMethodAsync('OnSwipeRight');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user