diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/AdminLayout.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/AdminLayout.razor index 7242ca52..0ebbae21 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/AdminLayout.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Layout/AdminLayout.razor @@ -1,13 +1,16 @@ @* - EN: Admin back-office layout — Sidebar + TopBar + Content area. - VI: Layout quản trị — Sidebar + TopBar + Vùng nội dung. - Design: pencil-design/src/pages/tPOS/admin/admin-dashboard.pen + EN: Admin back-office layout — 2-level sidebar (Admin vs Shop) + Content area. + VI: Layout quản trị — Sidebar 2 cấp (Admin vs Cửa hàng) + Vùng nội dung. + + Admin Level: Dashboard, Quản lý Cửa hàng, Hệ thống, Phân quyền, Cài đặt + Shop Level: Detected via URL /admin/shop/{shopId}/**, shows vertical-specific menu *@ @inherits LayoutComponentBase @inject NavigationManager NavigationManager @inject IJSRuntime JS @inject WebClientTpos.Client.Services.AuthStateService AuthState @inject WebClientTpos.Client.Services.AuthService AuthSvc +@using WebClientTpos.Client.Services @@ -28,61 +31,74 @@ @* Navigation *@ @* User profile *@ @@ -113,11 +129,73 @@ @code { private bool _sidebarOpen = false; + // EN: Shop context detection — parsed from URL + // VI: Phát hiện context cửa hàng — parse từ URL + private bool _isShopContext = false; + private string? _shopId; + private string _shopName = "Cửa hàng"; + private string? _shopCategory; + + protected override void OnInitialized() + { + NavigationManager.LocationChanged += OnLocationChanged; + DetectShopContext(); + } + protected override async Task OnAfterRenderAsync(bool firstRender) { // EN: Re-init Lucide icons after every render (Blazor navigation replaces DOM) // VI: Khởi tạo lại Lucide icons sau mỗi lần render (Blazor navigation thay đổi DOM) - try { await JS.InvokeVoidAsync("lucide.createIcons"); } catch { /* ignore if lucide not loaded */ } + try { await JS.InvokeVoidAsync("lucide.createIcons"); } catch { } + } + + private void OnLocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e) + { + DetectShopContext(); + StateHasChanged(); + } + + /// + /// EN: Detect if current URL is in shop context (/admin/shop/{shopId}/**). + /// VI: Phát hiện URL hiện tại có đang trong context cửa hàng không. + /// + private void DetectShopContext() + { + var uri = new Uri(NavigationManager.Uri); + var path = uri.AbsolutePath; + + // EN: Match pattern /admin/shop/{shopId}/** + // VI: Match pattern /admin/shop/{shopId}/** + if (path.StartsWith("/admin/shop/") && path.Length > "/admin/shop/".Length) + { + var remaining = path["/admin/shop/".Length..]; + var slashIndex = remaining.IndexOf('/'); + _shopId = slashIndex > 0 ? remaining[..slashIndex] : remaining; + _isShopContext = true; + + // EN: Try to read shop info from query params or localStorage (set by Dashboard click) + // VI: Đọc thông tin shop từ query params hoặc localStorage + // For now, use shopId as name fallback + _shopName = _shopName == "Cửa hàng" ? $"Shop #{_shopId?[..8]}" : _shopName; + } + else + { + _isShopContext = false; + _shopId = null; + } + } + + /// + /// EN: Set shop context info (called from pages that know shop details). + /// VI: Đặt thông tin context cửa hàng (gọi từ pages biết chi tiết shop). + /// + public void SetShopContext(string shopId, string name, string? category) + { + _shopId = shopId; + _shopName = name; + _shopCategory = category; + _isShopContext = true; + StateHasChanged(); } private void ToggleSidebar() => _sidebarOpen = !_sidebarOpen; @@ -154,4 +232,9 @@ LinesDefault = "#1F1F23" } }; + + public void Dispose() + { + NavigationManager.LocationChanged -= OnLocationChanged; + } } diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor index 16181cec..9deac69a 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Dashboard.razor @@ -5,9 +5,8 @@ @using WebClientTpos.Client.Services @* - EN: Admin Dashboard — overview of business metrics, stores, alerts, and recent activity. - VI: Dashboard Admin — tổng quan chỉ số kinh doanh, cửa hàng, cảnh báo, hoạt động gần đây. - Design: pencil-design/src/pages/tPOS/admin/admin-dashboard.pen + EN: Admin Dashboard — overview with real data from shops list. + VI: Dashboard Admin — tổng quan với dữ liệu thực từ danh sách shops. *@ Dashboard — GoodGo Admin @@ -25,7 +24,6 @@