Completato form attività e filtri

This commit is contained in:
2025-06-16 11:58:49 +02:00
parent 0032648e76
commit 7ca4de628b
44 changed files with 1241 additions and 924 deletions

View File

@@ -1,131 +0,0 @@
@using Template.Shared.Core.Dto
@using Template.Shared.Components.Layout
@using Template.Shared.Core.Interface
@inject IManageDataService manageData
<MudDialog Class="customDialog-form">
<DialogContent>
<HeaderLayout Cancel="true" OnCancel="() => MudDialog.Cancel()" 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>
</div>
</DialogContent>
</MudDialog>
@code {
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; }
[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 void OnAfterChangeValue()
{
if (OriginalModel.Equals(ActivityModel))
LabelSave = "Aggiorna";
StateHasChanged();
}
}

View File

@@ -1,61 +0,0 @@
.customDialog-form .content ::deep {
height: calc(100vh - (.6rem + 40px));
overflow: auto;
-ms-overflow-style: none;
scrollbar-width: none;
}
.customDialog-form .content::-webkit-scrollbar {
display: none;
}
.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;
}

View File

@@ -4,13 +4,14 @@
@using Template.Shared.Components.Layout
@using Template.Shared.Components.SingleElements
@using Template.Shared.Components.Layout.Spinner
@inject IManageDataService manageData
@inject IDialogService Dialog
@using Template.Shared.Components.Layout.BottomSheet
@inject IManageDataService ManageData
@inject IJSRuntime JS
<HeaderLayout Title="@CurrentMonth.ToString("MMMM yyyy", new System.Globalization.CultureInfo("it-IT")).FirstCharToUpper()"
ShowFilter="true"
ShowCalendarToggle="true"
OnFilterToggle="ToggleFilter"
OnCalendarToggle="ToggleExpanded"/>
<div @ref="weekSliderRef" class="container week-slider @(Expanded ? "expanded" : "") @(SliderAnimation)">
@@ -34,7 +35,7 @@
var day = new DateTime(CurrentMonth.Year, CurrentMonth.Month, d);
var isSelected = IsSameDay(day, SelectedDate);
var isToday = IsSameDay(day, DateTime.Today);
var events = GetEventsForDay(day);
var events = ReturnFilteredActivity(day);
<div class="day @(isSelected ? "selected" : (isToday ? "today" : ""))"
@onclick="() => SelezionaDataDalMese(day)">
@@ -69,10 +70,10 @@
<div class="day @(isSelected ? "selected" : (isToday ? "today" : ""))"
@onclick="() => SelezionaData(day)">
<div>@day.Day</div>
@if (GetEventsForDay(day).Any())
@if (ReturnFilteredActivity(day).Any())
{
<div class="event-dot-container" style="margin-top: 2px;">
@foreach (var cat in GetEventsForDay(day).Select(x => x.Category).Distinct())
@foreach (var cat in ReturnFilteredActivity(day).Select(x => x.Category).Distinct())
{
<div class="event-dot @cat.ConvertToHumanReadable()" title="@cat.ConvertToHumanReadable()"></div>
}
@@ -92,7 +93,7 @@
else if (FilteredActivities is { Count: > 0 })
{
<Virtualize Items="FilteredActivities" Context="activity">
<ActivityCard Activity="activity" />
<ActivityCard Activity="activity" ActivityChanged="OnActivityChanged"/>
</Virtualize>
}
else
@@ -101,6 +102,8 @@
}
</div>
<FilterActivity @bind-IsSheetVisible="OpenFilter" @bind-Filter="Filter" @bind-Filter:after="ApplyFilter"/>
@code {
// Stato UI
@@ -124,6 +127,10 @@
private int DaysInMonth => DateTime.DaysInMonth(CurrentMonth.Year, CurrentMonth.Month);
private int StartOffset => (int)CurrentMonth.DayOfWeek == 0 ? 6 : (int)CurrentMonth.DayOfWeek - 1;
//Filtri
private bool OpenFilter { get; set; }
private FilterActivityDTO Filter { get; set; } = new();
private int EndOffset
{
get
@@ -147,10 +154,17 @@
{
if (firstRender)
{
Filter.User = new HashSet<string> { UserSession.User.Username };
dotNetHelper = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("calendarSwipe.register", weekSliderRef, dotNetHelper);
_internalMonth = new DateTime(SelectedDate.Year, SelectedDate.Month, 1);
await LoadMonthData();
if (!Expanded)
ApplyFilter();
StateHasChanged();
}
}
@@ -249,7 +263,7 @@
// Carica tutte le attività del mese corrente visualizzato
var start = CurrentMonth;
var end = start.AddDays(DaysInMonth - 1);
var activities = await manageData.GetActivity(x =>
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();
@@ -272,7 +286,7 @@
await LoadMonthData();
}
FilteredActivities = GetEventsForDay(day);
ApplyFilter();
StateHasChanged();
}
@@ -280,7 +294,7 @@
private async Task SelezionaDataDalMese(DateTime day)
{
SelectedDate = day;
FilteredActivities = GetEventsForDay(day);
ApplyFilter();
// Chiudi la vista mese e passa alla settimana, con animazione
SliderAnimation = "collapse-animation";
StateHasChanged();
@@ -306,4 +320,63 @@
{
dotNetHelper?.Dispose();
}
private async Task OnActivityChanged(string activityId)
{
var newActivity = await ManageData.GetActivity(x => x.ActivityId.Equals(activityId));
var indexActivity = MonthActivities?.FindIndex(x => x.ActivityId.Equals(activityId));
if (indexActivity != null && !newActivity.IsNullOrEmpty())
{
MonthActivities![indexActivity.Value] = newActivity[0];
}
ApplyFilter();
StateHasChanged();
}
private void ToggleFilter()
{
OpenFilter = !OpenFilter;
StateHasChanged();
}
private void ApplyFilter()
{
FilteredActivities = GetEventsForDay(SelectedDate);
if (!Filter.ClearFilter)
{
FilteredActivities = GetEventsForDay(SelectedDate)?
.Where(x =>
(!Filter.Text.IsNullOrEmpty() && x.ActivityDescription != null && x.ActivityDescription.ContainsIgnoreCase(Filter.Text!)) ||
(x.ActivityTypeId != null && !Filter.Type.IsNullOrEmpty() && x.ActivityTypeId.Equals(Filter.Type)) ||
(x.ActivityResultId != null && !Filter.Result.IsNullOrEmpty() && x.ActivityResultId.Equals(Filter.Result)) ||
(x.UserName != null && !Filter.User.IsNullOrEmpty() && Filter.User!.Contains(x.UserName)) ||
(Filter.Category != null && x.Category.Equals(Filter.Category))
)
.ToList() ?? [];
}
StateHasChanged();
}
private List<ActivityDTO> 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);
}
}

View File

@@ -98,17 +98,23 @@
.container-button ::deep .button-settings { border: none !important; }
.container-button ::deep .button-settings .mud-icon-root {
border: 1px solid var(--mud-palette-gray-light);
border-radius: 6px;
padding: 2px;
min-width: 25px;
min-height: 25px;
box-shadow: inset 0 3px 5px rgba(200, 200, 200, 0.5);
}
.container-button ::deep .button-settings.green-icon .mud-icon-root { color: var(--mud-palette-success-darken); }
.container-button ::deep .button-settings.green-icon .mud-icon-root {
border: 1px solid var(--mud-palette-success);
background: hsl(from var(--mud-palette-success-lighten) h s 95%);
color: var(--mud-palette-success-darken);
}
.container-button ::deep .button-settings.red-icon .mud-icon-root { color: var(--mud-palette-error); }
.container-button ::deep .button-settings.red-icon .mud-icon-root {
border: 1px solid var(--mud-palette-error);
background: hsl(from var(--mud-palette-error-lighten) h s 95%);
color: var(--mud-palette-error-darken);
}
.container-button ::deep .button-settings .mud-button-label {
justify-content: flex-start;

View File

@@ -21,6 +21,7 @@
Elements["Commesse"] = false;
Elements["Clienti"] = false;
Elements["Prospect"] = false;
Elements["Impostazioni"] = false;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
@@ -34,7 +35,13 @@
await manageData.ClearDb();
}
await Task.WhenAll(RunAndTrack(SetActivity), RunAndTrack(SetClienti), RunAndTrack(SetProspect), RunAndTrack(SetCommesse));
await Task.WhenAll(
RunAndTrack(SetActivity),
RunAndTrack(SetClienti),
RunAndTrack(SetProspect),
RunAndTrack(SetCommesse),
RunAndTrack(SetSettings)
);
}
}
@@ -57,10 +64,7 @@
private async Task SetActivity()
{
await Task.Run(async () =>
{
await syncDb.GetAndSaveActivity(DateFilter);
});
await Task.Run(async () => { await syncDb.GetAndSaveActivity(DateFilter); });
Elements["Attività"] = true;
StateHasChanged();
@@ -68,10 +72,7 @@
private async Task SetClienti()
{
await Task.Run(async () =>
{
await syncDb.GetAndSaveClienti(DateFilter);
});
await Task.Run(async () => { await syncDb.GetAndSaveClienti(DateFilter); });
Elements["Clienti"] = true;
StateHasChanged();
@@ -79,10 +80,7 @@
private async Task SetProspect()
{
await Task.Run(async () =>
{
await syncDb.GetAndSaveProspect(DateFilter);
});
await Task.Run(async () => { await syncDb.GetAndSaveProspect(DateFilter); });
Elements["Prospect"] = true;
StateHasChanged();
@@ -90,13 +88,18 @@
private async Task SetCommesse()
{
await Task.Run(async () =>
{
await syncDb.GetAndSaveCommesse(DateFilter);
});
await Task.Run(async () => { await syncDb.GetAndSaveCommesse(DateFilter); });
Elements["Commesse"] = true;
StateHasChanged();
}
private async Task SetSettings()
{
await Task.Run(async () => { await syncDb.GetAndSaveSettings(DateFilter); });
Elements["Impostazioni"] = true;
StateHasChanged();
}
}