using FrontOffice.Main.Utilities; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; namespace FrontOffice.Main.Pages.Profile.Components; public partial class OrganizationChart : IAsyncDisposable { private NetworkTreeDto? _networkTree; private NetworkStatisticsDto? _statistics; private bool _isLoading = true; private bool _hasError = false; private int _selectedDepthValue = 3; private DotNetObjectReference? _dotNetHelper; private bool _chartNeedsInit = false; private bool _jsReady = false; // برای نگهداری شناسه کاربر فعلی که درختش نمایش داده شده private long? _currentViewUserId = null; // Stack برای بازگشت به عقب private Stack _navigationHistory = new(); private int _selectedDepth { get => _selectedDepthValue; set { if (_selectedDepthValue != value) { _selectedDepthValue = value; _ = OnDepthChanged(); } } } [Inject] private NetworkMembershipService NetworkService { get; set; } = default!; // JSRuntime is injected globally via _Imports.razor; protected override async Task OnInitializedAsync() { await LoadData(); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { _jsReady = true; } // Initialize chart after JS is ready and data is loaded if (_jsReady && _chartNeedsInit && _networkTree?.RootNode != null) { _chartNeedsInit = false; await InitializeChart(); } } private async Task LoadData() { _isLoading = true; _hasError = false; StateHasChanged(); try { // Load tree and statistics in parallel var treeTask = NetworkService.GetMyNetworkTreeAsync(_selectedDepth); var statsTask = NetworkService.GetMyNetworkStatisticsAsync(); await Task.WhenAll(treeTask, statsTask); _networkTree = await treeTask; _statistics = await statsTask; // Mark that chart needs to be initialized _chartNeedsInit = true; } catch (Exception ex) { Console.WriteLine($"Error loading network data: {ex.Message}"); _hasError = true; } finally { _isLoading = false; StateHasChanged(); } } private async Task InitializeChart() { if (_networkTree?.RootNode == null) return; try { _dotNetHelper = DotNetObjectReference.Create(this); var flatData = _networkTree.ToFlatArray(); await JSRuntime.InvokeVoidAsync("OrgChart.init", "org-chart-container", flatData, _dotNetHelper); } catch (Exception ex) { Console.WriteLine($"Error initializing chart: {ex.Message}"); } } private async Task RefreshData() { await LoadData(); if (_networkTree?.RootNode != null) { await InitializeChart(); } } private async Task OnDepthChanged() { await RefreshData(); } private async Task ExpandAll() { try { await JSRuntime.InvokeVoidAsync("OrgChart.expandAll"); } catch { } } private async Task CollapseAll() { try { await JSRuntime.InvokeVoidAsync("OrgChart.collapseAll"); } catch { } } private async Task CenterChart() { try { await JSRuntime.InvokeVoidAsync("OrgChart.center"); } catch { } } private async Task FitToScreen() { try { await JSRuntime.InvokeVoidAsync("OrgChart.fitToScreen"); } catch { } } private async Task ExportPng() { try { await JSRuntime.InvokeVoidAsync("OrgChart.exportPng"); } catch { } } /// /// Called from JavaScript when a node is clicked /// [JSInvokable] public async Task OnNodeClicked(long userId) { // اگر روی همان نود کلیک شده، کاری نکن if (_currentViewUserId == userId) return; // ذخیره نود فعلی در history برای بازگشت if (_currentViewUserId.HasValue) { _navigationHistory.Push(_currentViewUserId.Value); } await LoadSubordinateTree(userId); } /// /// بارگذاری درخت یک زیرمجموعه /// private async Task LoadSubordinateTree(long targetUserId) { _isLoading = true; StateHasChanged(); try { _networkTree = await NetworkService.GetSubordinateTreeAsync(targetUserId, _selectedDepth); _currentViewUserId = targetUserId; _chartNeedsInit = true; } catch (UnauthorizedAccessException) { // نمایش پیام خطا - این کاربر زیرمجموعه نیست Console.WriteLine("Unauthorized access to subordinate tree"); } catch (Exception ex) { Console.WriteLine($"Error loading subordinate tree: {ex.Message}"); } finally { _isLoading = false; StateHasChanged(); } } /// /// بازگشت به درخت قبلی /// private async Task GoBack() { if (_navigationHistory.Count > 0) { var previousUserId = _navigationHistory.Pop(); await LoadSubordinateTree(previousUserId); } else { // بازگشت به درخت خود کاربر _currentViewUserId = null; await LoadData(); if (_networkTree?.RootNode != null) { await InitializeChart(); } } } /// /// بازگشت به درخت اصلی (خود کاربر) /// private async Task GoToMyTree() { _navigationHistory.Clear(); _currentViewUserId = null; await LoadData(); if (_networkTree?.RootNode != null) { await InitializeChart(); } } public async ValueTask DisposeAsync() { try { await JSRuntime.InvokeVoidAsync("OrgChart.dispose"); } catch { } _dotNetHelper?.Dispose(); } }