@page "/User/{CodContact}/{IsContact:bool}" @attribute [Authorize] @using AutoMapper @using salesbook.Shared.Components.Layout @using salesbook.Shared.Core.Entity @using salesbook.Shared.Core.Interface @using salesbook.Shared.Components.Layout.Spinner @using salesbook.Shared.Core.Dto @using salesbook.Shared.Components.SingleElements @using salesbook.Shared.Core.Dto.Activity @using salesbook.Shared.Core.Dto.JobProgress @using salesbook.Shared.Core.Dto.PageState @using salesbook.Shared.Core.Interface.IntegryApi @implements IAsyncDisposable @inject IManageDataService ManageData @inject IMapper Mapper @inject IDialogService Dialog @inject IIntegryApiService IntegryApiService @inject UserPageState UserState @if (IsLoading) { } else {
@UtilityString.ExtractInitials(Anag.RagSoc)
@Anag.RagSoc @if (!string.IsNullOrEmpty(Anag.Indirizzo)) { @Anag.Indirizzo } @if (!string.IsNullOrEmpty(Anag.Cap) && !string.IsNullOrEmpty(Anag.Citta) && !string.IsNullOrEmpty(Anag.Prov)) { @($"{Anag.Cap} - {Anag.Citta} ({Anag.Prov})") }
@if (PersRif?.Count > 0) {
@foreach (var person in PersRif) { @if (person != PersRif.Last()) {
} }
}
Aggiungi contatto
@if (IsLoadingCommesse) { } else if (Commesse?.Count == 0) { } else if (Commesse != null) {
@if (IsLoadingSteps) { } @foreach (var commessa in CurrentPageCommesse) {
@if (Steps.TryGetValue(commessa.CodJcom, out var steps)) { } else { @if (IsLoadingStep(commessa.CodJcom)) { } }
} @if (TotalPagesCommesse > 1) {
5 10 15
}
}
@if (ActivityIsLoading) { } else if (ActivityList?.Count == 0) { } else if (ActivityList != null) {
@foreach (var activity in CurrentPageActivity) { } @if (TotalPagesActivity > 1) {
5 15 30
}
}
} @code { [Parameter] public string CodContact { get; set; } = string.Empty; [Parameter] public bool IsContact { get; set; } // Dati principali private ContactDTO Anag { get; set; } = new(); private List? PersRif { get; set; } private List? Commesse { get; set; } private List ActivityList { get; set; } = []; private StbUser? Agente { get; set; } private Dictionary?> Steps { get; set; } = new(); // Stati di caricamento private bool IsLoading { get; set; } = true; private bool IsLoadingCommesse { get; set; } = true; private bool ActivityIsLoading { get; set; } = true; private bool IsLoadingSteps { get; set; } private readonly HashSet _loadingSteps = []; // Gestione tab private int ActiveTab { get; set; } // Paginazione e filtri per COMMESSE private int _selectedPageCommesse = 1; private int _selectedPageSizeCommesse = 5; private string _searchTermCommesse = string.Empty; private List _filteredCommesse = []; // Paginazione e filtri per ATTIVITĄ private int _currentPageActivity = 1; private int _selectedPageSizeActivity = 5; private string _searchTermActivity = string.Empty; private List _filteredActivity = []; // Cancellation tokens per gestire le richieste asincrone private CancellationTokenSource? _loadingCts; private CancellationTokenSource? _stepsCts; // Timer per il debounce della ricerca private Timer? _searchTimerCommesse; private Timer? _searchTimerActivity; private const int SearchDelayMs = 300; #region Properties per Commesse private int SelectedPageCommesse { get => _selectedPageCommesse; set { if (_selectedPageCommesse == value) return; _selectedPageCommesse = value; _ = LoadStepsForCurrentPageAsync(); } } private int SelectedPageSizeCommesse { get => _selectedPageSizeCommesse; set { if (_selectedPageSizeCommesse == value) return; _selectedPageSizeCommesse = value; _selectedPageCommesse = 1; ApplyFiltersCommesse(); _ = LoadStepsForCurrentPageAsync(); } } private string SearchTermCommesse { get => _searchTermCommesse; set { if (_searchTermCommesse == value) return; _searchTermCommesse = value; _searchTimerCommesse?.Dispose(); _searchTimerCommesse = new Timer(async _ => await InvokeAsync(ApplyFiltersCommesse), null, SearchDelayMs, Timeout.Infinite); } } private List FilteredCommesse { get => _filteredCommesse; set { _filteredCommesse = value; StateHasChanged(); } } private int TotalPagesCommesse => FilteredCommesse.Count == 0 ? 1 : (int)Math.Ceiling(FilteredCommesse.Count / (double)SelectedPageSizeCommesse); private IEnumerable CurrentPageCommesse => FilteredCommesse.Skip((SelectedPageCommesse - 1) * SelectedPageSizeCommesse).Take(SelectedPageSizeCommesse); #endregion #region Properties per Attivitą private int CurrentPageActivityIndex { get => _currentPageActivity; set { if (_currentPageActivity == value) return; _currentPageActivity = value; StateHasChanged(); } } private int SelectedPageSizeActivity { get => _selectedPageSizeActivity; set { if (_selectedPageSizeActivity == value) return; _selectedPageSizeActivity = value; _currentPageActivity = 1; ApplyFiltersActivity(); } } private string SearchTermActivity { get => _searchTermActivity; set { if (_searchTermActivity == value) return; _searchTermActivity = value; _searchTimerActivity?.Dispose(); _searchTimerActivity = new Timer(async _ => await InvokeAsync(ApplyFiltersActivity), null, SearchDelayMs, Timeout.Infinite); } } private List FilteredActivity { get => _filteredActivity; set { _filteredActivity = value; StateHasChanged(); } } private int TotalPagesActivity => FilteredActivity.Count == 0 ? 1 : (int)Math.Ceiling(FilteredActivity.Count / (double)SelectedPageSizeActivity); private IEnumerable CurrentPageActivity => FilteredActivity.Skip((CurrentPageActivityIndex - 1) * SelectedPageSizeActivity).Take(SelectedPageSizeActivity); #endregion #region Lifecycle Methods protected override async Task OnInitializedAsync() { try { _loadingCts = new CancellationTokenSource(); if (UserState.CodUser?.Equals(CodContact) == true) { LoadDataFromSession(); } else { await LoadDataAsync(); } } catch (Exception ex) { Console.WriteLine($"Errore in OnInitializedAsync: {ex.Message}"); } finally { IsLoading = false; StateHasChanged(); } } public async ValueTask DisposeAsync() { _loadingCts?.CancelAsync(); _loadingCts?.Dispose(); _stepsCts?.CancelAsync(); _stepsCts?.Dispose(); _searchTimerCommesse?.DisposeAsync(); _searchTimerActivity?.DisposeAsync(); } #endregion #region Data Loading Methods private async Task LoadDataAsync() { try { await LoadAnagAsync(); await LoadPersRifAsync(); _ = LoadActivity(); if (!string.IsNullOrEmpty(Anag.CodVage)) { Agente = (await ManageData.GetTable(x => x.UserCode != null && x.UserCode.Equals(Anag.CodVage))) .LastOrDefault(); } SaveDataToSession(); _ = Task.Run(async () => await LoadCommesseAsync()); } catch (Exception ex) { Console.WriteLine($"Errore nel caricamento dati: {ex.Message}"); } } private async Task LoadAnagAsync() { if (IsContact) { var clie = (await ManageData.GetTable(x => x.CodAnag!.Equals(CodContact))).Last(); Anag = Mapper.Map(clie); } else { var pros = (await ManageData.GetTable(x => x.CodPpro!.Equals(CodContact))).Last(); Anag = Mapper.Map(pros); } } private async Task LoadPersRifAsync() { if (IsContact) { var pers = await ManageData.GetTable(x => x.CodAnag!.Equals(Anag.CodContact)); PersRif = Mapper.Map>(pers); } else { var pers = await ManageData.GetTable(x => x.CodPpro!.Equals(Anag.CodContact)); PersRif = Mapper.Map>(pers); } } private async Task LoadActivity() { await Task.Run(async () => { var activities = await IntegryApiService.RetrieveActivity(new CRMRetrieveActivityRequestDTO { CodAnag = Anag.CodContact }); ActivityList = Mapper.Map>(activities) .OrderByDescending(x => (x.EffectiveTime ?? x.EstimatedTime) ?? x.DataInsAct ).ToList(); }); UserState.Activitys = ActivityList; ApplyFiltersActivity(); ActivityIsLoading = false; StateHasChanged(); } private async Task LoadCommesseAsync() { try { IsLoadingCommesse = true; Commesse = await ManageData.GetTable(x => x.CodAnag != null && x.CodAnag.Equals(CodContact)); Commesse = Commesse? .OrderByDescending(x => x.CodJcom) .ToList(); UserState.Commesse = Commesse; ApplyFiltersCommesse(); await LoadStepsForCurrentPageAsync(); } catch (Exception ex) { Console.WriteLine($"Errore nel caricamento commesse: {ex.Message}"); } finally { IsLoadingCommesse = false; await InvokeAsync(StateHasChanged); } } private void LoadDataFromSession() { Anag = UserState.Anag; PersRif = UserState.PersRif; Commesse = UserState.Commesse; Agente = UserState.Agente; Steps = UserState.Steps; ActivityList = UserState.Activitys; ApplyFiltersCommesse(); ApplyFiltersActivity(); IsLoadingCommesse = false; ActivityIsLoading = false; } private void SaveDataToSession() { UserState.CodUser = CodContact; UserState.Anag = Anag; UserState.PersRif = PersRif; UserState.Agente = Agente; UserState.Steps = Steps; UserState.Activitys = ActivityList; } #endregion #region Steps Loading Methods private async Task LoadStepsForCurrentPageAsync() { if (CurrentPageCommesse?.Any() != true) return; try { _stepsCts?.Cancel(); _stepsCts = new CancellationTokenSource(); var token = _stepsCts.Token; IsLoadingSteps = true; var tasksToLoad = new List(); var semaphore = new SemaphoreSlim(3); // Limita a 3 richieste simultanee foreach (var commessa in CurrentPageCommesse.Where(c => !Steps.ContainsKey(c.CodJcom))) { if (token.IsCancellationRequested) break; tasksToLoad.Add(LoadStepForCommessaAsync(commessa.CodJcom, semaphore, token)); } if (tasksToLoad.Any()) { await Task.WhenAll(tasksToLoad); UserState.Steps = Steps; } } catch (OperationCanceledException) { // Operazione annullata, non fare nulla } catch (Exception ex) { Console.WriteLine($"Errore nel caricamento steps: {ex.Message}"); } finally { IsLoadingSteps = false; await InvokeAsync(StateHasChanged); } } private async Task LoadStepForCommessaAsync(string codJcom, SemaphoreSlim semaphore, CancellationToken token) { await semaphore.WaitAsync(token); try { _loadingSteps.Add(codJcom); await InvokeAsync(StateHasChanged); var jobProgress = await IntegryApiService.RetrieveJobProgress(codJcom); if (!token.IsCancellationRequested) { Steps[codJcom] = jobProgress.Steps; await InvokeAsync(StateHasChanged); } } catch (Exception ex) { Console.WriteLine($"Errore nel caricamento step per {codJcom}: {ex.Message}"); if (!token.IsCancellationRequested) { Steps[codJcom] = null; } } finally { _loadingSteps.Remove(codJcom); semaphore.Release(); } } private bool IsLoadingStep(string codJcom) => _loadingSteps.Contains(codJcom); #endregion #region UI Methods private void SwitchTab(int tabIndex) { ActiveTab = tabIndex; if (tabIndex == 1 && Commesse == null) { _ = Task.Run(async () => await LoadCommesseAsync()); } else if (tabIndex == 1 && Steps.IsNullOrEmpty()) { _ = Task.Run(async () => await LoadStepsForCurrentPageAsync()); } else if (tabIndex == 2 && ActivityList?.Count == 0) { _ = Task.Run(async () => await LoadActivity()); } } private void ApplyFiltersCommesse() { if (Commesse == null) { FilteredCommesse = []; return; } var filtered = Commesse.AsEnumerable(); if (!string.IsNullOrWhiteSpace(SearchTermCommesse)) { var searchLower = SearchTermCommesse.ToLowerInvariant(); filtered = filtered.Where(c => c.CodJcom?.ToLowerInvariant().Contains(searchLower) == true || c.Descrizione?.ToLowerInvariant().Contains(searchLower) == true || c.CodAnag?.ToLowerInvariant().Contains(searchLower) == true); } FilteredCommesse = filtered.ToList(); if (SelectedPageCommesse > TotalPagesCommesse && TotalPagesCommesse > 0) _selectedPageCommesse = 1; _ = LoadStepsForCurrentPageAsync(); } private void ApplyFiltersActivity() { var filtered = ActivityList.AsEnumerable(); if (!string.IsNullOrWhiteSpace(SearchTermActivity)) { var searchLower = SearchTermActivity.ToLowerInvariant(); filtered = filtered.Where(a => a.ActivityDescription?.ToLowerInvariant().Contains(searchLower) == true || a.ActivityId?.ToLowerInvariant().Contains(searchLower) == true); } FilteredActivity = filtered.ToList(); if (CurrentPageActivityIndex > TotalPagesActivity && TotalPagesActivity > 0) { _currentPageActivity = 1; } } private void ClearSearchCommesse() { SearchTermCommesse = string.Empty; ApplyFiltersCommesse(); } private void ClearSearchActivity() { SearchTermActivity = string.Empty; ApplyFiltersActivity(); } #endregion #region Modal Methods private async Task OpenPersRifForm() { var result = await ModalHelpers.OpenPersRifForm(Dialog, null, Anag, PersRif); if (result is { Canceled: false, Data: not null } && result.Data.GetType() == typeof(PersRifDTO)) { await LoadPersRifAsync(); UserState.PersRif = PersRif; } } private async Task OpenUserForm(ContactDTO anag) { var result = await ModalHelpers.OpenUserForm(Dialog, anag); if (result is { Canceled: false }) { await LoadAnagAsync(); SaveDataToSession(); } } #endregion }