Completato form attività e filtri
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Entity
|
||||
@using Template.Shared.Core.Helpers.Enum
|
||||
@using Template.Shared.Core.Interface
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<div class="bottom-sheet-backdrop @(IsSheetVisible ? "show" : "")" @onclick="CloseBottomSheet"></div>
|
||||
|
||||
<div class="bottom-sheet-container @(IsSheetVisible ? "show" : "")">
|
||||
<div class="bottom-sheet">
|
||||
<div class="title">
|
||||
<MudText Typo="Typo.h6">
|
||||
<b>Filtri</b>
|
||||
</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Close" OnClick="CloseBottomSheet"/>
|
||||
</div>
|
||||
|
||||
<div class="input-card clearButton">
|
||||
<MudTextField T="string?" Placeholder="Cerca..." Variant="Variant.Text" @bind-Value="Filter.Text" DebounceInterval="500"/>
|
||||
|
||||
<MudIconButton Class="closeIcon" Icon="@Icons.Material.Filled.Close" OnClick="() => Filter.Text = null"/>
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<div class="form-container">
|
||||
<span class="disable-full-width">Assegnata a</span>
|
||||
|
||||
<MudSelectExtended SearchBox="true"
|
||||
ItemCollection="Users.Select(x => x.UserName).ToList()"
|
||||
SelectAllPosition="SelectAllPosition.NextToSearchBox"
|
||||
SelectAll="true"
|
||||
NoWrap="true"
|
||||
MultiSelection="true"
|
||||
MultiSelectionTextFunc="@(new Func<List<string>, string>(GetMultiSelectionUser))"
|
||||
FullWidth="true" T="string"
|
||||
Variant="Variant.Text"
|
||||
Virtualize="true"
|
||||
@bind-SelectedValues="Filter.User"
|
||||
Class="customIcon-select"
|
||||
AdornmentIcon="@Icons.Material.Filled.Code"/>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span class="disable-full-width">Tipo</span>
|
||||
|
||||
<MudSelectExtended FullWidth="true"
|
||||
T="string?"
|
||||
Variant="Variant.Text"
|
||||
@bind-Value="Filter.Type"
|
||||
Class="customIcon-select"
|
||||
AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var type in ActivityType)
|
||||
{
|
||||
<MudSelectItemExtended Class="custom-item-select" Value="@type.ActivityTypeId">@type.ActivityTypeId</MudSelectItemExtended>
|
||||
}
|
||||
</MudSelectExtended>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span class="disable-full-width">Esito</span>
|
||||
|
||||
<MudSelectExtended FullWidth="true"
|
||||
T="string?"
|
||||
Variant="Variant.Text"
|
||||
@bind-Value="Filter.Result"
|
||||
Class="customIcon-select"
|
||||
AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var result in ActivityResult)
|
||||
{
|
||||
<MudSelectItemExtended Class="custom-item-select" Value="@result.ActivityResultId">@result.ActivityResultId</MudSelectItemExtended>
|
||||
}
|
||||
</MudSelectExtended>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span class="disable-full-width">Categoria</span>
|
||||
|
||||
<MudSelectExtended FullWidth="true"
|
||||
T="ActivityCategoryEnum?"
|
||||
Variant="Variant.Text"
|
||||
@bind-Value="Filter.Category"
|
||||
Class="customIcon-select"
|
||||
AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var category in CategoryList)
|
||||
{
|
||||
<MudSelectItemExtended T="ActivityCategoryEnum?" Class="custom-item-select" Value="@category">@category.ConvertToHumanReadable()</MudSelectItemExtended>
|
||||
}
|
||||
</MudSelectExtended>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button-section">
|
||||
<MudButton OnClick="() => Filter = new FilterActivityDTO()" Variant="Variant.Outlined" Color="Color.Error">Pulisci</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="OnFilterButton">Filtra</MudButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public bool IsSheetVisible { get; set; }
|
||||
[Parameter] public EventCallback<bool> IsSheetVisibleChanged { get; set; }
|
||||
|
||||
[Parameter] public FilterActivityDTO Filter { get; set; }
|
||||
[Parameter] public EventCallback<FilterActivityDTO> FilterChanged { get; set; }
|
||||
|
||||
private List<StbActivityResult> ActivityResult { get; set; } = [];
|
||||
private List<StbActivityType> ActivityType { get; set; } = [];
|
||||
private List<StbUser> Users { get; set; } = [];
|
||||
private List<ActivityCategoryEnum> CategoryList { get; set; } = [];
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (IsSheetVisible)
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private string GetMultiSelectionUser(List<string> selectedValues)
|
||||
{
|
||||
return $"{selectedValues.Count} Utent{(selectedValues.Count != 1 ? "i selezionati" : "e selezionato")}";
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
Users = await manageData.GetTable<StbUser>();
|
||||
ActivityResult = await manageData.GetTable<StbActivityResult>();
|
||||
ActivityType = await manageData.GetTable<StbActivityType>(x => x.FlagTipologia.Equals("A"));
|
||||
CategoryList = ActivityCategoryHelper.AllActivityCategory;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void CloseBottomSheet()
|
||||
{
|
||||
IsSheetVisible = false;
|
||||
IsSheetVisibleChanged.InvokeAsync(IsSheetVisible);
|
||||
}
|
||||
|
||||
private void OnFilterButton()
|
||||
{
|
||||
FilterChanged.InvokeAsync(Filter);
|
||||
CloseBottomSheet();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
.bottom-sheet-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(165, 165, 165, 0.5);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.3s ease;
|
||||
z-index: 1002;
|
||||
}
|
||||
|
||||
.bottom-sheet-backdrop.show {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.bottom-sheet-container {
|
||||
position: fixed;
|
||||
bottom: -100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transition: bottom 0.3s ease;
|
||||
z-index: 1003;
|
||||
}
|
||||
|
||||
.bottom-sheet-container.show {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.bottom-sheet {
|
||||
background-color: var(--mud-palette-surface);
|
||||
border-top-left-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
padding: 4px 16px 16px;
|
||||
box-shadow: 0 -2px 10px rgba(165, 165, 165, 0.5);
|
||||
}
|
||||
|
||||
.clearButton ::deep .mud-icon-button {
|
||||
padding: 4px !important;
|
||||
}
|
||||
|
||||
.bottom-sheet ::deep .closeIcon .mud-icon-root {
|
||||
border-radius: 50%;
|
||||
padding: 2px;
|
||||
min-width: 15px;
|
||||
min-height: 15px;
|
||||
padding: 4px;
|
||||
background: var(--mud-palette-gray-light);
|
||||
color: var(--mud-palette-surface);
|
||||
}
|
||||
|
||||
.button-section {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
gap: .75rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
@@ -22,11 +22,7 @@
|
||||
{
|
||||
@if (ShowFilter)
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.FilterAlt" Color="Color.Dark"/>
|
||||
}
|
||||
@if (ShowNotifications)
|
||||
{
|
||||
@* <MudIconButton Icon="@Icons.Material.Filled.Notifications" Color="Color.Dark"/> *@
|
||||
<MudIconButton OnClick="OnFilterToggle" Icon="@Icons.Material.Outlined.FilterAlt" Color="Color.Dark" />
|
||||
}
|
||||
@if (ShowCalendarToggle)
|
||||
{
|
||||
@@ -53,6 +49,8 @@
|
||||
[Parameter] public bool Back { get; set; }
|
||||
[Parameter] public string BackTo { get; set; } = "";
|
||||
|
||||
[Parameter] public EventCallback OnFilterToggle { get; set; }
|
||||
|
||||
[Parameter] public bool Cancel { get; set; }
|
||||
[Parameter] public EventCallback OnCancel { get; set; }
|
||||
[Parameter] public string? LabelSave { get; set; }
|
||||
@@ -76,7 +74,7 @@
|
||||
}
|
||||
|
||||
await JS.InvokeVoidAsync("goBack");
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
23
Template.Shared/Components/Layout/Overlay/SaveOverlay.razor
Normal file
23
Template.Shared/Components/Layout/Overlay/SaveOverlay.razor
Normal file
@@ -0,0 +1,23 @@
|
||||
@using Template.Shared.Components.Layout.Spinner
|
||||
<MudOverlay Visible="VisibleOverlay" LightBackground="true">
|
||||
@if (SuccessAnimation)
|
||||
{
|
||||
<div class="success-checkmark">
|
||||
<div class="check-icon">
|
||||
<span class="icon-line line-tip"></span>
|
||||
<span class="icon-line line-long"></span>
|
||||
<div class="icon-circle"></div>
|
||||
<div class="icon-fix"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<SpinnerLayout/>
|
||||
}
|
||||
</MudOverlay>
|
||||
|
||||
@code {
|
||||
[Parameter] public required bool SuccessAnimation { get; set; }
|
||||
[Parameter] public required bool VisibleOverlay { get; set; }
|
||||
}
|
||||
156
Template.Shared/Components/Layout/Overlay/SaveOverlay.razor.css
Normal file
156
Template.Shared/Components/Layout/Overlay/SaveOverlay.razor.css
Normal file
@@ -0,0 +1,156 @@
|
||||
.success-checkmark {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.success-checkmark .check-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
position: relative;
|
||||
border-radius: 50%;
|
||||
box-sizing: content-box;
|
||||
border: 4px solid var(--mud-palette-success);
|
||||
}
|
||||
|
||||
.success-checkmark .check-icon::before {
|
||||
top: 3px;
|
||||
left: -2px;
|
||||
width: 30px;
|
||||
transform-origin: 100% 50%;
|
||||
border-radius: 100px 0 0 100px;
|
||||
}
|
||||
|
||||
.success-checkmark .check-icon::after {
|
||||
top: 0;
|
||||
left: 30px;
|
||||
width: 60px;
|
||||
transform-origin: 0 50%;
|
||||
border-radius: 0 100px 100px 0;
|
||||
animation: rotate-circle 4.25s ease-in;
|
||||
}
|
||||
|
||||
.success-checkmark .check-icon::before,
|
||||
.success-checkmark .check-icon::after {
|
||||
content: '';
|
||||
height: 100px;
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.icon-line {
|
||||
height: 5px;
|
||||
background-color: var(--mud-palette-success);
|
||||
display: block;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.icon-line.line-tip {
|
||||
top: 46px;
|
||||
left: 14px;
|
||||
width: 25px;
|
||||
transform: rotate(45deg);
|
||||
animation: icon-line-tip 0.75s;
|
||||
}
|
||||
|
||||
.icon-line.line-long {
|
||||
top: 38px;
|
||||
right: 8px;
|
||||
width: 47px;
|
||||
transform: rotate(-45deg);
|
||||
animation: icon-line-long 0.75s;
|
||||
}
|
||||
|
||||
|
||||
.icon-circle {
|
||||
top: -4px;
|
||||
left: -4px;
|
||||
z-index: 10;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
box-sizing: content-box;
|
||||
border: 4px solid var(--mud-palette-success);
|
||||
}
|
||||
|
||||
.icon-fix {
|
||||
top: 8px;
|
||||
width: 5px;
|
||||
left: 26px;
|
||||
z-index: 1;
|
||||
height: 85px;
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
@keyframes rotate-circle {
|
||||
0% { transform: rotate(-45deg); }
|
||||
|
||||
5% { transform: rotate(-45deg); }
|
||||
|
||||
12% { transform: rotate(-405deg); }
|
||||
|
||||
100% { transform: rotate(-405deg); }
|
||||
}
|
||||
|
||||
@keyframes icon-line-tip {
|
||||
0% {
|
||||
width: 0;
|
||||
left: 1px;
|
||||
top: 19px;
|
||||
}
|
||||
|
||||
54% {
|
||||
width: 0;
|
||||
left: 1px;
|
||||
top: 19px;
|
||||
}
|
||||
|
||||
70% {
|
||||
width: 50px;
|
||||
left: -8px;
|
||||
top: 37px;
|
||||
}
|
||||
|
||||
84% {
|
||||
width: 17px;
|
||||
left: 21px;
|
||||
top: 48px;
|
||||
}
|
||||
|
||||
100% {
|
||||
width: 25px;
|
||||
left: 14px;
|
||||
top: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes icon-line-long {
|
||||
0% {
|
||||
width: 0;
|
||||
right: 46px;
|
||||
top: 54px;
|
||||
}
|
||||
|
||||
65% {
|
||||
width: 0;
|
||||
right: 46px;
|
||||
top: 54px;
|
||||
}
|
||||
|
||||
84% {
|
||||
width: 55px;
|
||||
right: 0px;
|
||||
top: 35px;
|
||||
}
|
||||
|
||||
100% {
|
||||
width: 47px;
|
||||
right: 8px;
|
||||
top: 38px;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Interface
|
||||
@using Template.Shared.Components.Layout.Spinner
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<div class="calendar">
|
||||
@if (Load)
|
||||
{
|
||||
<SpinnerLayout FullScreen="false" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@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>
|
||||
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public required DateTime? Date { get; set; }
|
||||
[Parameter] public EventCallback<DateTime?> DateChanged { get; set; }
|
||||
|
||||
private List<ActivityDTO>? Activities { get; set; }
|
||||
private bool Load { get; set; } = true;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await LoadData();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
Load = true;
|
||||
StateHasChanged();
|
||||
|
||||
await Task.Delay(500);
|
||||
var refreshActivity = await RefreshActivity();
|
||||
Activities = refreshActivity;
|
||||
Load = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task<List<ActivityDTO>> RefreshActivity()
|
||||
{
|
||||
var activityDto = await Task.Run(async () =>
|
||||
{
|
||||
return (await manageData.GetActivity(x =>
|
||||
(x.EffectiveDate == null && x.EstimatedDate.Equals(Date)) || x.EffectiveDate.Equals(Date)))
|
||||
.OrderBy(x => x.EffectiveDate ?? x.EstimatedDate)
|
||||
.ToList();
|
||||
});
|
||||
|
||||
return activityDto;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
.calendar {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.calendar::-webkit-scrollbar { display: none; }
|
||||
|
||||
.calendar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Interface
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<div class="calendar-activity">
|
||||
<div class="calendar">
|
||||
@foreach (var nomeGiorno in _giorniSettimana)
|
||||
{
|
||||
<div class="calendar-header">@nomeGiorno</div>
|
||||
}
|
||||
|
||||
@for (var i = 0; i < StartDays; i++)
|
||||
{
|
||||
<div class="calendar-day disabled @(i == 0 ? "radiusTopLeft" : "")"></div>
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
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-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
|
||||
{
|
||||
[Parameter] public required DateTime Date { get; set; }
|
||||
[Parameter] public EventCallback<DateTime> DateChanged { 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; }
|
||||
private int EndDays { get; set; }
|
||||
|
||||
readonly string[] _giorniSettimana = ["Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"];
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await ChangeMonth();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await ChangeMonth();
|
||||
}
|
||||
|
||||
private async Task ChangeMonth()
|
||||
{
|
||||
var firstDay = Date;
|
||||
DaysInMonth = DateTime.DaysInMonth(firstDay.Year, firstDay.Month);
|
||||
|
||||
var dayOfWeek = (int)firstDay.DayOfWeek;
|
||||
StartDays = dayOfWeek == 0 ? 6 : dayOfWeek - 1;
|
||||
|
||||
var tempTotalCell = (int)Math.Ceiling((double)(DaysInMonth + StartDays) / 7);
|
||||
var totalCell = tempTotalCell * 7;
|
||||
EndDays = totalCell - (DaysInMonth + StartDays);
|
||||
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
// Load = true;
|
||||
// StateHasChanged();
|
||||
|
||||
await Task.Delay(500);
|
||||
var refreshActivity = await RefreshActivity();
|
||||
ActivityList = refreshActivity;
|
||||
// Load = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task<List<ActivityDTO>> RefreshActivity()
|
||||
{
|
||||
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,101 +0,0 @@
|
||||
.calendar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
}
|
||||
|
||||
.calendar-header, .calendar-day {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
min-height: 65px;
|
||||
font-size: 0.85rem;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.calendar-day { border: 1px solid var(--mud-palette-gray-light); }
|
||||
|
||||
.calendar-day.disabled { border: 1px solid hsl(from var(--mud-palette-gray-light) h s 88%); }
|
||||
|
||||
.calendar-header {
|
||||
font-weight: bold;
|
||||
min-height: 25px;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.today > .calendar-day-wrapper > .titleDay {
|
||||
background-color: var(--mud-palette-primary);
|
||||
color: var(--mud-palette-appbar-text);
|
||||
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%;
|
||||
position: absolute;
|
||||
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);
|
||||
}
|
||||
|
||||
.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 {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.radiusTopLeft { border-top-left-radius: 12px; }
|
||||
|
||||
.radiusTopRight { border-top-right-radius: 12px; }
|
||||
|
||||
.radiusBottomLeft { border-bottom-left-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,88 +0,0 @@
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Interface
|
||||
@using Template.Shared.Components.Layout.Spinner
|
||||
@inject IManageDataService manageData
|
||||
|
||||
<div class="calendar">
|
||||
@{
|
||||
DateTime? currentDate = null;
|
||||
}
|
||||
|
||||
@if (Load)
|
||||
{
|
||||
<SpinnerLayout FullScreen="false"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
@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>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public required DateRange Date { get; set; }
|
||||
[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)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await LoadData();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await LoadData();
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
Load = true;
|
||||
StateHasChanged();
|
||||
|
||||
await Task.Delay(500);
|
||||
var refreshActivity = await RefreshActivity();
|
||||
Activities = refreshActivity;
|
||||
Load = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task<List<ActivityDTO>> RefreshActivity()
|
||||
{
|
||||
var activityDto = await Task.Run(async () =>
|
||||
{
|
||||
return (await manageData.GetActivity(x =>
|
||||
(x.EffectiveDate == null && x.EstimatedDate >= Date.Start && x.EstimatedDate <= Date.End) ||
|
||||
(x.EffectiveDate >= Date.Start && x.EffectiveDate <= Date.End)
|
||||
))
|
||||
.OrderBy(x => x.EffectiveDate ?? x.EstimatedDate)
|
||||
.ToList();
|
||||
});
|
||||
|
||||
return activityDto;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
.calendar {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.calendar::-webkit-scrollbar { display: none; }
|
||||
|
||||
.calendar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.week-info {
|
||||
background: var(--mud-palette-action-disabled-background);
|
||||
width: 100%;
|
||||
padding: .3rem .5rem;
|
||||
border-radius: 8px;
|
||||
text-transform: capitalize;
|
||||
font-weight: 700;
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Core.Entity
|
||||
@using Template.Shared.Core.Helpers.Enum
|
||||
@inject IDialogService Dialog
|
||||
|
||||
<div class="activity-card @Activity.Category.ConvertToHumanReadable()" @onclick="() => ModalHelpers.OpenActivityForm(Dialog, Activity.ActivityId)">
|
||||
<div class="activity-card @Activity.Category.ConvertToHumanReadable()" @onclick="OpenActivity">
|
||||
<div class="activity-left-section">
|
||||
<div class="activity-body-section">
|
||||
<div class="title-section">
|
||||
@@ -63,6 +64,7 @@
|
||||
|
||||
@code {
|
||||
[Parameter] public ActivityDTO Activity { get; set; } = new();
|
||||
[Parameter] public EventCallback<string> ActivityChanged { get; set; }
|
||||
|
||||
private TimeSpan? Durata { get; set; }
|
||||
|
||||
@@ -75,4 +77,14 @@
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private async Task OpenActivity()
|
||||
{
|
||||
var result = await ModalHelpers.OpenActivityForm(Dialog, Activity.ActivityId);
|
||||
|
||||
if (result is { Canceled: false, Data: not null } && result.Data.GetType() == typeof(StbActivity))
|
||||
{
|
||||
await ActivityChanged.InvokeAsync(((StbActivity)result.Data).ActivityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,6 @@
|
||||
}
|
||||
|
||||
.activity-info-section {
|
||||
width: min-content;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
@using Template.Shared.Core.Dto
|
||||
@using Template.Shared.Components.Layout
|
||||
@using Template.Shared.Core.Entity
|
||||
@using Template.Shared.Core.Interface
|
||||
@using Template.Shared.Components.Layout.Overlay
|
||||
@inject IManageDataService ManageData
|
||||
@inject INetworkService NetworkService
|
||||
@inject IIntegryApiService IntegryApiService
|
||||
|
||||
<MudDialog Class="customDialog-form">
|
||||
<DialogContent>
|
||||
<HeaderLayout Cancel="true" OnCancel="() => MudDialog.Cancel()" LabelSave="@LabelSave" OnSave="Save" ShowNotifications="false" Title="@(IsNew ? "Nuova" : $"{ActivityModel.ActivityId}")" />
|
||||
|
||||
<div class="content">
|
||||
<div class="input-card">
|
||||
<MudTextField ReadOnly="IsView" T="string?" Placeholder="Descrizione" Variant="Variant.Text" Lines="3" @bind-Value="ActivityModel.ActivityDescription" @bind-Value:after="OnAfterChangeValue" DebounceInterval="500" OnDebounceIntervalElapsed="OnAfterChangeValue" />
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<div class="form-container">
|
||||
<MudInput ReadOnly="IsView" T="string?" Placeholder="Cliente" @bind-Value="ActivityModel.Cliente" @bind-Value:after="OnAfterChangeValue" />
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<MudInput ReadOnly="IsView" 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 ReadOnly="IsView" T="DateTime?" Format="yyyy-MM-ddTHH:mm" InputType="InputType.DateTimeLocal" @bind-Value="ActivityModel.EstimatedTime" @bind-Value:after="OnAfterChangeValue" DebounceInterval="500" OnDebounceIntervalElapsed="OnAfterChangeValue" />
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span>Fine</span>
|
||||
|
||||
<MudTextField ReadOnly="IsView" T="DateTime?" Format="yyyy-MM-ddTHH:mm" InputType="InputType.DateTimeLocal" @bind-Value="ActivityModel.EstimatedEndtime" @bind-Value:after="OnAfterChangeValue" DebounceInterval="500" OnDebounceIntervalElapsed="OnAfterChangeValue" />
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span>Avviso</span>
|
||||
|
||||
<MudSwitch ReadOnly="IsView" T="bool" Disabled="true" Color="Color.Primary" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<div class="form-container">
|
||||
<span class="disable-full-width">Assegnata a</span>
|
||||
|
||||
<MudSelectExtended FullWidth="true" ReadOnly="IsView" T="string?" Variant="Variant.Text" @bind-Value="ActivityModel.UserName" @bind-Value:after="OnAfterChangeValue" Class="customIcon-select" AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var user in Users)
|
||||
{
|
||||
<MudSelectItemExtended Class="custom-item-select" Value="@user.UserName">@user.FullName</MudSelectItemExtended>
|
||||
}
|
||||
</MudSelectExtended>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span class="disable-full-width">Tipo</span>
|
||||
|
||||
<MudSelectExtended ReadOnly="IsView" FullWidth="true" T="string?" Variant="Variant.Text" @bind-Value="ActivityModel.ActivityTypeId" @bind-Value:after="OnAfterChangeValue" Class="customIcon-select" AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var type in ActivityType)
|
||||
{
|
||||
<MudSelectItemExtended Class="custom-item-select" Value="@type.ActivityTypeId">@type.ActivityTypeId</MudSelectItemExtended>
|
||||
}
|
||||
</MudSelectExtended>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="form-container">
|
||||
<span class="disable-full-width">Esito</span>
|
||||
|
||||
<MudSelectExtended ReadOnly="IsView" FullWidth="true" T="string?" Variant="Variant.Text" @bind-Value="ActivityModel.ActivityResultId" @bind-Value:after="OnAfterChangeValue" Class="customIcon-select" AdornmentIcon="@Icons.Material.Filled.Code">
|
||||
@foreach (var result in ActivityResult)
|
||||
{
|
||||
<MudSelectItemExtended Class="custom-item-select" Value="@result.ActivityResultId">@result.ActivityResultId</MudSelectItemExtended>
|
||||
}
|
||||
</MudSelectExtended>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-card">
|
||||
<MudTextField ReadOnly="IsView" T="string?" Placeholder="Note" Variant="Variant.Text" Lines="4" @bind-Value="ActivityModel.Note" @bind-Value:after="OnAfterChangeValue" DebounceInterval="500" OnDebounceIntervalElapsed="OnAfterChangeValue" />
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</MudDialog>
|
||||
|
||||
<SaveOverlay VisibleOverlay="VisibleOverlay" SuccessAnimation="SuccessAnimation" />
|
||||
|
||||
@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<StbActivityResult> ActivityResult { get; set; } = [];
|
||||
private List<StbActivityType> ActivityType { get; set; } = [];
|
||||
private List<StbUser> Users { get; set; } = [];
|
||||
|
||||
private bool IsNew => Id.IsNullOrEmpty();
|
||||
private bool IsView => !IsNew && !NetworkService.IsNetworkAvailable();
|
||||
|
||||
private string? LabelSave { get; set; }
|
||||
|
||||
//Overlay for save
|
||||
private bool VisibleOverlay { get; set; }
|
||||
private bool SuccessAnimation { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_ = LoadData();
|
||||
|
||||
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 Save()
|
||||
{
|
||||
VisibleOverlay = true;
|
||||
StateHasChanged();
|
||||
|
||||
var newActivity = await IntegryApiService.SaveActivity(ActivityModel);
|
||||
await ManageData.InsertOrUpdate(newActivity);
|
||||
|
||||
SuccessAnimation = true;
|
||||
StateHasChanged();
|
||||
|
||||
await Task.Delay(1250);
|
||||
|
||||
MudDialog.Close(newActivity);
|
||||
}
|
||||
|
||||
private async Task LoadData()
|
||||
{
|
||||
Users = await ManageData.GetTable<StbUser>();
|
||||
ActivityResult = await ManageData.GetTable<StbActivityResult>();
|
||||
ActivityType = await ManageData.GetTable<StbActivityType>(x => x.FlagTipologia.Equals("A"));
|
||||
}
|
||||
|
||||
private void OnAfterChangeValue()
|
||||
{
|
||||
LabelSave = !OriginalModel.Equals(ActivityModel) ? "Aggiorna" : null;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user