From ceed3b7defdb27ef7bca8e952eb32ca130899402 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Sat, 28 Feb 2026 07:04:32 +0700 Subject: [PATCH] chore(web-client): delete 9 orphaned pages replaced by ShopPage sections --- .../Admin/Customer/CustomerDatabase.razor | 137 ------- .../Admin/Inventory/InventoryDashboard.razor | 171 -------- .../Pages/Admin/Product/MenuBuilder.razor | 104 ----- .../Pages/Admin/Product/ProductCatalog.razor | 194 ---------- .../Pages/Admin/Product/ProductCreate.razor | 241 ------------ .../Pages/Admin/Staff/StaffCreate.razor | 101 ----- .../Pages/Admin/Staff/StaffDirectory.razor | 168 -------- .../Pages/Admin/Store/StoreDetail.razor | 276 ------------- .../Pages/Admin/Store/StoreSettings.razor | 364 ------------------ 9 files changed, 1756 deletions(-) delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Customer/CustomerDatabase.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Inventory/InventoryDashboard.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/MenuBuilder.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCatalog.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCreate.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffCreate.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffDirectory.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreDetail.razor delete mode 100644 apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreSettings.razor diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Customer/CustomerDatabase.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Customer/CustomerDatabase.razor deleted file mode 100644 index 3907c9df..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Customer/CustomerDatabase.razor +++ /dev/null @@ -1,137 +0,0 @@ -@page "/admin/customers" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services - -@* - EN: Customer database — real data from membership_service via BFF. - VI: Cơ sở dữ liệu khách hàng — dữ liệu thực từ membership_service qua BFF. -*@ - -Khách hàng — GoodGo Admin - -
-
-

Khách hàng

-

@_members.Count thành viên

-
-
- -
-
- -@* ═══ SUMMARY ═══ *@ -
-
-
-
- -
-
- @_members.Count - Tổng thành viên -
-
-
-
- -
-
- @_members.Count(m => m.CurrentLevel >= 3) - VIP -
-
-
-
- -
-
- @_members.Where(m => m.CreatedAt >= DateTime.UtcNow.AddDays(-30)).Count() - Mới (30 ngày) -
-
-
- - @* ═══ MEMBERS TABLE ═══ *@ - @if (IsLoading) - { -
-
-

Đang tải dữ liệu...

-
- } - else if (!_members.Any()) - { -
-
- -
-

Chưa có thành viên

-

Khách hàng sẽ tự động trở thành thành viên khi mua hàng

-
- } - else - { -
-
- - - - - - - - - - - - - @foreach (var m in _members) - { - - - - - - - - - } - -
IDCấp bậcEXPGiới tínhQuốc giaNgày tham gia
@m.Id.ToString()[..8]... - - - @(m.LevelName ?? $"Level {m.CurrentLevel}") - - @m.TotalExpEarned.ToString("N0")@(m.Gender ?? "—")@(m.CountryCode ?? "—")@m.CreatedAt.ToString("dd/MM/yyyy")
-
-
- } -
- -@code { - private string _searchQuery = ""; - private List _members = new(); - - protected override async Task OnInitializedAsync() - { - IsLoading = true; - try { _members = await DataService.GetMembersAsync(); } - catch { } - finally { IsLoading = false; } - } - - private static string GetLevelColor(int level) => level switch - { - 1 => "#94A3B8", - 2 => "#22C55E", - 3 => "#3B82F6", - 4 => "#F59E0B", - 5 => "#FF5C00", - _ => "#8B5CF6" - }; -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Inventory/InventoryDashboard.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Inventory/InventoryDashboard.razor deleted file mode 100644 index be0d8409..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Inventory/InventoryDashboard.razor +++ /dev/null @@ -1,171 +0,0 @@ -@page "/admin/inventory" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services - -@* - EN: Inventory dashboard — real data from inventory_service via BFF. - VI: Bảng điều khiển tồn kho — dữ liệu thực từ inventory_service qua BFF. -*@ - -Kho hàng — GoodGo Admin - -
-
-

Kho hàng

-

@_items.Count mặt hàng @(_selectedShopId.HasValue ? $"• {_shopName}" : "• Tất cả cửa hàng")

-
-
- - -
-
- -@* ═══ SUMMARY CARDS ═══ *@ -
-
-
-
- -
-
- @_items.Count - Tổng mặt hàng -
-
-
-
- -
-
- @_items.Count(i => i.Quantity > i.ReorderLevel) - Đủ hàng -
-
-
-
- -
-
- @_items.Count(i => i.Quantity <= i.ReorderLevel && i.Quantity > 0) - Sắp hết -
-
-
-
- -
-
- @_items.Count(i => i.Quantity <= 0) - Hết hàng -
-
-
- - @* ═══ INVENTORY TABLE ═══ *@ - @if (IsLoading) - { -
-
-

Đang tải tồn kho...

-
- } - else if (!FilteredItems.Any()) - { -
-
- -
-

Chưa có dữ liệu tồn kho

-

Tồn kho sẽ tự động cập nhật khi có giao dịch mua/bán

-
- } - else - { -
-
- - - - - - - - - - - - @foreach (var item in FilteredItems) - { - - - - - - - - } - -
Sản phẩmTồn khoĐặt trướcNgưỡngTrạng thái
@(item.ProductName ?? "N/A")@item.Quantity@item.ReservedQuantity@item.ReorderLevel - @{ var status = GetStockStatus(item); } - - - @status.label - -
-
-
- } -
- -@code { - private string _searchQuery = ""; - private Guid? _selectedShopId; - private string _shopName = ""; - private List _items = new(); - private List _shops = new(); - - private IEnumerable FilteredItems => _items - .Where(i => string.IsNullOrEmpty(_searchQuery) || - (i.ProductName ?? "").Contains(_searchQuery, StringComparison.OrdinalIgnoreCase)); - - protected override async Task OnInitializedAsync() - { - IsLoading = true; - try - { - _shops = await DataService.GetShopsAsync(); - _items = await DataService.GetInventoryAsync(_selectedShopId); - } - catch { } - finally { IsLoading = false; } - } - - private async Task OnShopFilterChanged(ChangeEventArgs e) - { - var val = e.Value?.ToString(); - _selectedShopId = Guid.TryParse(val, out var id) ? id : null; - _shopName = _shops.FirstOrDefault(s => s.Id == _selectedShopId)?.Name ?? ""; - IsLoading = true; - try { _items = await DataService.GetInventoryAsync(_selectedShopId); } - catch { } - finally { IsLoading = false; } - } - - private static (string css, string label) GetStockStatus(PosDataService.InventoryItemInfo item) - { - if (item.Quantity <= 0) return ("admin-status-badge--offline", "Hết hàng"); - if (item.Quantity <= item.ReorderLevel) return ("admin-status-badge--warning", "Sắp hết"); - return ("admin-status-badge--online", "Đủ hàng"); - } -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/MenuBuilder.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/MenuBuilder.razor deleted file mode 100644 index b78439e0..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/MenuBuilder.razor +++ /dev/null @@ -1,104 +0,0 @@ -@page "/admin/products/menu-builder" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services - -Menu Builder — GoodGo Admin - -
-
-

Menu Builder

-

@_categories.Count danh mục • @_products.Count sản phẩm

-
-
- -
-
- -
- @* Category sidebar *@ -
-
-

Danh mục

-
- - @foreach (var cat in _categories) - { - var catName = cat.Name; - var count = _products.Count(p => string.Equals(p.CategoryName, catName, StringComparison.OrdinalIgnoreCase)); - - } -
-
-
- - @* Products grid *@ -
- @if (IsLoading) - { -
- } - else if (!FilteredProducts.Any()) - { -

Chưa có sản phẩm

- } - else - { -
- @foreach (var p in FilteredProducts) - { -
-
-
-
@p.Name
-
@(p.CategoryName ?? "—")
-
@p.Price.ToString("N0")₫
-
-
- } -
- } -
-
- -@code { - private List _products = new(); - private List _categories = new(); - private List _shops = new(); - private string? _selectedCategory; - private Guid? _selectedShopId; - - private IEnumerable FilteredProducts => _selectedCategory == null - ? _products - : _products.Where(p => string.Equals(p.CategoryName, _selectedCategory, StringComparison.OrdinalIgnoreCase)); - - protected override async Task OnInitializedAsync() - { - IsLoading = true; - try - { - _shops = await DataService.GetShopsAsync(); - _products = await DataService.GetAllProductsAsync(); - _categories = await DataService.GetAllCategoriesAsync(); - } - catch { } finally { IsLoading = false; } - } - - private async Task OnShopFilterChanged(ChangeEventArgs e) - { - _selectedShopId = Guid.TryParse(e.Value?.ToString(), out var id) ? id : null; - IsLoading = true; - try - { - _products = await DataService.GetAllProductsAsync(_selectedShopId); - _categories = await DataService.GetAllCategoriesAsync(_selectedShopId); - } - catch { } finally { IsLoading = false; } - } - - private void SelectCategory(string? cat) { _selectedCategory = cat; } -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCatalog.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCatalog.razor deleted file mode 100644 index 024ab142..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCatalog.razor +++ /dev/null @@ -1,194 +0,0 @@ -@page "/admin/products" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services - -@* - EN: Product catalog — grid view with real data from catalog-service via BFF. - VI: Danh mục sản phẩm — grid view, dữ liệu thực từ catalog-service qua BFF. -*@ - -Sản phẩm — GoodGo Admin - -@* ═══ TOP BAR ═══ *@ -
-
-

Sản phẩm & Menu

-

@_products.Count sản phẩm @(_selectedShopId.HasValue ? $"• {_shopName}" : "• Tất cả cửa hàng")

-
-
- - @* ── Shop filter dropdown ── *@ - - -
-
- -@* ═══ CATEGORY TABS ═══ *@ -
- - @foreach (var cat in _categoryNames) - { - - } -
- -@* ═══ CONTENT ═══ *@ -
- - @if (IsLoading) - { -
-
-

Đang tải sản phẩm...

-
- } - else if (!FilteredProducts.Any()) - { -
-
- -
-

Chưa có sản phẩm nào

-

Thêm sản phẩm đầu tiên để bắt đầu bán hàng

- -
- } - else - { - @* ── Product Grid ── *@ -
- @foreach (var prod in FilteredProducts) - { -
-
- -
-
-
-
-
@prod.Name
-
@(prod.CategoryName ?? "Không phân loại")
-
-
- - @(prod.IsActive ? "Có" : "Hết") -
-
-
- @FormatPrice(prod.Price) - @if (!string.IsNullOrEmpty(prod.Sku)) - { - SKU: @prod.Sku - } -
-
-
- } -
- } -
- -@code { - private string _category = "all"; - private string _searchQuery = ""; - private Guid? _selectedShopId; - private string _shopName = ""; - private List _products = new(); - private List _shops = new(); - private List _categoryNames = new(); - - // EN: Filtered products by category and search query. - // VI: Sản phẩm đã lọc theo danh mục và từ khóa tìm kiếm. - private IEnumerable FilteredProducts => _products - .Where(p => _category == "all" || (p.CategoryName ?? "Khác") == _category) - .Where(p => string.IsNullOrEmpty(_searchQuery) || - p.Name.Contains(_searchQuery, StringComparison.OrdinalIgnoreCase) || - (p.Sku ?? "").Contains(_searchQuery, StringComparison.OrdinalIgnoreCase)); - - protected override async Task OnInitializedAsync() - { - IsLoading = true; - try - { - _shops = await DataService.GetShopsAsync(); - _products = await DataService.GetAllProductsAsync(_selectedShopId); - BuildCategoryTabs(); - } - catch { } - finally { IsLoading = false; } - } - - private async Task OnShopFilterChanged(ChangeEventArgs e) - { - var val = e.Value?.ToString(); - _selectedShopId = Guid.TryParse(val, out var id) ? id : null; - _shopName = _shops.FirstOrDefault(s => s.Id == _selectedShopId)?.Name ?? ""; - IsLoading = true; - try - { - _products = await DataService.GetAllProductsAsync(_selectedShopId); - BuildCategoryTabs(); - _category = "all"; - } - catch { } - finally { IsLoading = false; } - } - - private void BuildCategoryTabs() - { - _categoryNames = _products - .Select(p => p.CategoryName ?? "Khác") - .Distinct() - .OrderBy(c => c) - .ToList(); - } - - // EN: Format price with K suffix / VI: Format giá với hậu tố K - private static string FormatPrice(decimal price) => - price >= 1000 ? $"{price / 1000:0.#}K" : $"{price:N0}đ"; - - private static string GetTypeIcon(string? type) => type?.ToLowerInvariant() switch - { - "preparedfood" => "coffee", - "physical" => "package", - "service" => "sparkles", - _ => "package" - }; - - private static string GetTypeColor(string? type) => type?.ToLowerInvariant() switch - { - "preparedfood" => "#FF5C00", - "physical" => "#3B82F6", - "service" => "#8B5CF6", - _ => "#FF5C00" - }; - - private static string GetTypeBgColor(string? type) => type?.ToLowerInvariant() switch - { - "preparedfood" => "rgba(255,92,0,0.08)", - "physical" => "rgba(59,130,246,0.08)", - "service" => "rgba(139,92,246,0.08)", - _ => "rgba(255,92,0,0.08)" - }; -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCreate.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCreate.razor deleted file mode 100644 index 00218ae2..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Product/ProductCreate.razor +++ /dev/null @@ -1,241 +0,0 @@ -@page "/admin/products/create" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services - -@* - EN: Create product — form with real API submission via BFF. - VI: Thêm sản phẩm — form gửi dữ liệu thực qua BFF. -*@ - -Thêm sản phẩm — GoodGo Admin - -@* ═══ TOP BAR ═══ *@ -
-
- -
-

Thêm sản phẩm mới

-

Điền thông tin sản phẩm

-
-
-
- - -
-
- -@* ═══ CONTENT ═══ *@ -
- - @* LEFT: Main form *@ -
- - @* Success/Error messages *@ - @if (!string.IsNullOrEmpty(_message)) - { -
-
- - @_message -
-
- } - - @* Basic Info *@ -
-
-

- - Thông tin cơ bản -

-
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
-
- - -
-
-
- - @* Pricing *@ -
-
-

- - Giá bán -

-
-
-
-
- - -
-
-
-
-
- - @* RIGHT: Image & Shop *@ -
- @* Image Upload (placeholder) *@ -
-
-

Hình ảnh

-
-
-
- - Kéo thả hoặc click để upload - PNG, JPG tối đa 2MB -
-
-
- - @* Quick preview *@ - @if (!string.IsNullOrEmpty(_name)) - { -
-
-

- - Xem trước -

-
-
-
-
- -
-
-
@_name
-
@GetTypeLabel(_type)
-
@FormatPrice(_price)
-
-
-
-
- } -
-
- -@code { - private string _shopId = ""; - private string _name = ""; - private string _description = ""; - private decimal _price; - private string _type = "PreparedFood"; - private string _sku = ""; - private string _message = ""; - private bool _isSuccess; - private bool _isSaving; - private List _shops = new(); - - protected override async Task OnInitializedAsync() - { - try { _shops = await DataService.GetShopsAsync(); } - catch { } - } - - private async Task HandleSubmit() - { - _message = ""; - - // EN: Validate required fields / VI: Kiểm tra trường bắt buộc - if (string.IsNullOrWhiteSpace(_shopId) || !Guid.TryParse(_shopId, out var shopId)) - { _message = "Vui lòng chọn cửa hàng."; _isSuccess = false; return; } - if (string.IsNullOrWhiteSpace(_name)) - { _message = "Vui lòng nhập tên sản phẩm."; _isSuccess = false; return; } - if (_price <= 0) - { _message = "Giá bán phải lớn hơn 0."; _isSuccess = false; return; } - - _isSaving = true; - try - { - var req = new PosDataService.CreateProductRequest( - shopId, _name.Trim(), _description.Trim(), _price, - _type, string.IsNullOrWhiteSpace(_sku) ? null : _sku.Trim(), null); - - var ok = await DataService.CreateProductAsync(req); - if (ok) - { - _message = $"Đã tạo sản phẩm \"{_name}\" thành công!"; - _isSuccess = true; - // Reset form - _name = ""; _description = ""; _price = 0; _sku = ""; - } - else - { - _message = "Không thể tạo sản phẩm. Vui lòng thử lại."; - _isSuccess = false; - } - } - catch (Exception ex) - { - _message = $"Lỗi: {ex.Message}"; - _isSuccess = false; - } - finally { _isSaving = false; } - } - - private static string FormatPrice(decimal price) => - price >= 1000 ? $"{price / 1000:0.#}K" : price > 0 ? $"{price:N0}đ" : "--"; - - private static string GetTypeIcon(string? type) => type switch - { - "PreparedFood" => "coffee", - "Physical" => "package", - "Service" => "sparkles", - _ => "package" - }; - - private static string GetTypeLabel(string? type) => type switch - { - "PreparedFood" => "Đồ ăn/uống", - "Physical" => "Hàng hóa", - "Service" => "Dịch vụ", - _ => "Sản phẩm" - }; -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffCreate.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffCreate.razor deleted file mode 100644 index 320dabf1..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffCreate.razor +++ /dev/null @@ -1,101 +0,0 @@ -@page "/admin/staff/create" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services - -Thêm nhân viên — GoodGo Admin - -
-
- -
-

Thêm nhân viên mới

-

Điền thông tin nhân viên

-
-
-
- - -
-
- -
-
- @if (!string.IsNullOrEmpty(_message)) - { -
-
- - @_message -
-
- } - -
-
-

Thông tin nhân viên

-
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
-
-
- -@code { - private string _empCode = "", _role = "Cashier", _phone = "", _email = "", _message = ""; - private bool _isSuccess, _isSaving; - private List _roles = new(); - - protected override async Task OnInitializedAsync() - { - try { _roles = await DataService.GetStaffRolesAsync(); if (_roles.Any()) _role = _roles[0].Name; } catch { } - } - - private async Task HandleSubmit() - { - _message = ""; - if (string.IsNullOrWhiteSpace(_role)) { _message = "Vui lòng chọn vai trò."; _isSuccess = false; return; } - _isSaving = true; - try - { - // EN: Use first merchant or Guid.Empty / VI: Dùng merchant đầu tiên hoặc Guid.Empty - var shops = await DataService.GetShopsAsync(); - var merchantId = Guid.Empty; // Will be set correctly when merchant context is available - var ok = await DataService.CreateStaffAsync(new(merchantId, _empCode.Trim(), _phone.Trim(), _email.Trim(), _role)); - if (ok) { _message = "Đã thêm nhân viên thành công!"; _isSuccess = true; _empCode = ""; _phone = ""; _email = ""; } - else { _message = "Không thể thêm nhân viên."; _isSuccess = false; } - } - catch (Exception ex) { _message = $"Lỗi: {ex.Message}"; _isSuccess = false; } - finally { _isSaving = false; } - } -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffDirectory.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffDirectory.razor deleted file mode 100644 index 36d0a6f2..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Staff/StaffDirectory.razor +++ /dev/null @@ -1,168 +0,0 @@ -@page "/admin/staff" -@layout AdminLayout -@inherits AdminBase -@inject WebClientTpos.Client.Services.PosDataService DataService -@using WebClientTpos.Client.Services - -@* - EN: Staff directory — real data from BFF, grid of staff cards with search & filter. - VI: Danh bạ nhân sự — dữ liệu thật từ BFF, grid thẻ nhân viên, tìm kiếm & lọc. -*@ - -Quản lý nhân sự — GoodGo Admin - -@* ═══ TOP BAR ═══ *@ -
-
-

Quản lý nhân sự

-

Tất cả cửa hàng • @_staffList.Count nhân viên

-
-
- - -
-
- -@* ═══ TABS ═══ *@ -
- - - - -
- -@* ═══ CONTENT ═══ *@ -@if (_loading) -{ -
- -
-} -else if (!FilteredStaff.Any()) -{ -
- - Chưa có nhân viên nào - -
-} -else -{ -
- @foreach (var staff in FilteredStaff) - { -
-
-
- @GetInitials(staff.Email ?? staff.EmployeeCode ?? "?") -
-
- - @GetStatusLabel(staff.Status) -
-
-
- @(staff.Email ?? staff.EmployeeCode ?? "Nhân viên") - @(staff.Role ?? "—") • @(staff.ShopName ?? "Chưa gán") -
-
-
-
@(staff.EmployeeCode ?? "—")
-
Mã NV
-
-
-
@(staff.Phone ?? "—")
-
Điện thoại
-
-
-
@FormatDate(staff.JoinedAt)
-
Ngày vào
-
-
-
- } -
-} - -@code { - private bool _loading = true; - private string _activeTab = "all"; - private List _staffList = new(); - - private IEnumerable FilteredStaff - { - get - { - var list = _activeTab switch - { - "active" => _staffList.Where(s => s.Status == "Active"), - "invited" => _staffList.Where(s => s.Status == "Invited"), - "inactive" => _staffList.Where(s => s.Status == "Inactive" || s.Status == "Terminated"), - _ => _staffList - }; - if (!string.IsNullOrEmpty(SearchQuery)) - list = list.Where(s => (s.Email ?? "").Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) - || (s.EmployeeCode ?? "").Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) - || (s.Phone ?? "").Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) - || (s.ShopName ?? "").Contains(SearchQuery, StringComparison.OrdinalIgnoreCase)); - return list; - } - } - - protected override async Task OnInitializedAsync() - { - try { _staffList = await DataService.GetStaffAsync(); } - catch { _staffList = new(); } - finally { _loading = false; } - } - - private static string GetInitials(string value) - { - if (value.Contains('@')) value = value.Split('@')[0]; - return value.Length >= 2 ? value[..2].ToUpper() : value.ToUpper(); - } - - private static string GetAvatarColor(string role) => role switch - { - "Cashier" => "#3B82F6", - "Waiter" => "#22C55E", - "Manager" => "#8B5CF6", - "Admin" => "#FF5C00", - _ => "#6B7280" - }; - - private static string GetStatusCss(string? status) => status switch - { - "Active" => "admin-status-badge--online", - "Invited" => "admin-status-badge--setup", - _ => "admin-status-badge--offline" - }; - - private static string GetStatusLabel(string? status) => status switch - { - "Active" => "Đang làm", - "Invited" => "Chờ xác nhận", - "Inactive" => "Tạm nghỉ", - "Terminated" => "Đã nghỉ", - _ => status ?? "—" - }; - - private static string FormatDate(DateTime? dt) => dt.HasValue ? dt.Value.ToString("dd/MM/yy") : "—"; -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreDetail.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreDetail.razor deleted file mode 100644 index 6545cda8..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreDetail.razor +++ /dev/null @@ -1,276 +0,0 @@ -@page "/admin/stores/{Id}" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services - -@* - EN: Store detail — overview with KPIs (real data from API). - VI: Chi tiết cửa hàng — tổng quan KPI (dữ liệu thực từ API). -*@ - -@(_shop?.Name ?? "Cửa hàng") — GoodGo Admin - -@* ═══ TOP BAR ═══ *@ -
-
- -
-

@(_shop?.Name ?? "Đang tải...")

-

@(_shop?.Category ?? "—") • @(_shop?.Slug ?? "—")

-
-
-
- @if (_shop != null) - { -
- - @GetStatusLabel(_shop.Status) -
- } - - -
-
- -@* ═══ CONTENT ═══ *@ -
- - @if (IsLoading) - { -
-
-

Đang tải thông tin cửa hàng...

-
- } - else if (_shop == null) - { -
- -

Không tìm thấy cửa hàng

-

Cửa hàng không tồn tại hoặc đã bị xóa.

- -
- } - else - { - @* ── Store Info Card ── *@ -
-
-
- -
-
-
@_shop.Name
-
@_shop.Slug • @(_shop.Category ?? "—")
- @if (!string.IsNullOrEmpty(_shop.Description)) - { -
@_shop.Description
- } -
-
- @if (!string.IsNullOrEmpty(_shop.Phone)) - { -
- @_shop.Phone -
- } - @if (!string.IsNullOrEmpty(_shop.Email)) - { -
- @_shop.Email -
- } -
-
-
- - @* ── KPI ROW (placeholder — chưa có dữ liệu order/revenue) ── *@ -
-
-
-
- -
-
-
--
-
Doanh thu tháng
-
- -
-
-
- -
-
-
--
-
Đơn hàng tháng
-
- -
-
-
- -
-
-
--
-
Giá trị TB / đơn
-
- -
-
-
- -
-
-
--
-
Đánh giá TB
-
-
- - @* ── BOTTOM: Chart + Right Column ── *@ -
- - @* LEFT: Revenue Chart Placeholder *@ -
-
-

- - Doanh thu 7 ngày gần nhất -

-
- - -
-
-
-
- -

Chưa có dữ liệu doanh thu

-

Dữ liệu sẽ hiển thị khi có đơn hàng

-
-
-
- - @* RIGHT COLUMN *@ -
- - @* Recent Orders Placeholder *@ -
-
-

- - Đơn gần nhất -

-
-
- -

Chưa có đơn hàng nào

-
-
- - @* Shop Quick Info *@ -
-
-

- - Thông tin -

-
-
-
- Trạng thái - @GetStatusLabel(_shop.Status) -
-
- Ngành hàng - @(_shop.Category ?? "—") -
-
- Slug - @(_shop.Slug) -
- @if (!string.IsNullOrEmpty(_shop.Phone)) - { -
- Điện thoại - @_shop.Phone -
- } - @if (!string.IsNullOrEmpty(_shop.Email)) - { -
- Email - @_shop.Email -
- } -
-
-
-
- } -
- -@code { - [Parameter] public string Id { get; set; } = ""; - - private PosDataService.ShopInfo? _shop; - - protected override async Task OnInitializedAsync() - { - IsLoading = true; - try - { - if (Guid.TryParse(Id, out var shopId)) - { - _shop = await DataService.GetShopByIdAsync(shopId); - } - } - catch - { - _shop = null; - } - finally - { - IsLoading = false; - } - } - - private static string GetStatusBadgeClass(string? status) => status?.ToLowerInvariant() switch - { - "published" or "active" => "online", - "draft" or "setup" => "setup", - "inactive" or "paused" => "paused", - _ => "setup" - }; - - private static string GetStatusLabel(string? status) => status?.ToLowerInvariant() switch - { - "published" or "active" => "Đang mở", - "draft" or "setup" => "Thiết lập", - "inactive" or "paused" => "Tạm dừng", - "closed" => "Đã đóng", - _ => status ?? "—" - }; - - private static string GetShopIcon(string? category) => category?.ToLowerInvariant() switch - { - "foodbeverage" or "café" or "cafe" or "coffee" => "coffee", - "restaurant" or "nhà hàng" => "utensils", - "entertainment" or "karaoke" => "mic", - "beauty" or "spa" => "sparkles", - "retail" => "shopping-bag", - _ => "store" - }; -} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreSettings.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreSettings.razor deleted file mode 100644 index 58bd137c..00000000 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Store/StoreSettings.razor +++ /dev/null @@ -1,364 +0,0 @@ -@page "/admin/stores/{Id}/settings" -@layout AdminLayout -@inherits AdminBase -@inject PosDataService DataService -@using WebClientTpos.Client.Services -@using WebClientTpos.Shared.DTOs - -@* - EN: Store settings — tabs for general, payment, receipts, integrations (real data from API). - VI: Cài đặt cửa hàng — tabs cho chung, thanh toán, hóa đơn, tích hợp (dữ liệu thực từ API). -*@ - -Cài đặt cửa hàng — GoodGo Admin - -@* ═══ TOP BAR ═══ *@ -
-
- -
-

Cài đặt cửa hàng

-

@(_shop?.Name ?? "Đang tải...") — Quản lý cài đặt

-
-
-
- @if (!string.IsNullOrEmpty(_successMessage)) - { - - - @_successMessage - - } - @if (!string.IsNullOrEmpty(_errorMessage)) - { - @_errorMessage - } - -
-
- -@* ═══ TABS ═══ *@ -
- - - - -
- -@* ═══ CONTENT ═══ *@ -
- - @if (IsLoading) - { -
-
-

Đang tải cài đặt cửa hàng...

-
- } - else if (_shop == null) - { -
- -

Không tìm thấy cửa hàng

- -
- } - else - { - @if (_tab == "general") - { - @* General Settings *@ -
-
-

Thông tin cửa hàng

-
-
-
-
- - -
-
- - - Không thể thay đổi slug sau khi tạo -
-
-
-
- - -
-
- - -
-
-
- - -
-
-
- - -
-
- - -
-
-
-
- - @* Danger Zone *@ -
-
-

- - Vùng nguy hiểm -

-
-
-
-
-
Tạm dừng cửa hàng
-
Cửa hàng sẽ ngừng hoạt động tạm thời
-
- -
-
-
-
-
Đóng cửa hàng
-
Không thể hoàn tác, cửa hàng sẽ bị đóng vĩnh viễn
-
- -
-
-
- } - - @if (_tab == "payment") - { - @* Payment Methods *@ -
-
-

Phương thức thanh toán

-
-
- @foreach (var pm in _paymentMethods) - { -
-
- -
-
@pm.Name
-
@pm.Desc
-
-
- -
- } -
-
- } - - @if (_tab == "receipt") - { -
-
-

Mẫu hóa đơn

-
-
-
- - -
-
- - -
-
- - -
-
-
- } - - @if (_tab == "integrations") - { -
-
-

Tích hợp bên thứ ba

-
-
-
-
- -
-
GrabFood
-
Đồng bộ đơn hàng delivery
-
-
- -
-
-
- -
-
ShopeeFood
-
Đồng bộ đơn hàng delivery
-
-
- -
-
-
- -
-
Kế toán (Misa)
-
Xuất hóa đơn điện tử
-
-
- -
-
-
- } - } -
- -@code { - [Inject] private MerchantApiService MerchantApi { get; set; } = default!; - [Parameter] public string Id { get; set; } = ""; - - private PosDataService.ShopInfo? _shop; - private string _tab = "general"; - private bool _isSaving = false; - private string? _successMessage; - private string? _errorMessage; - - // EN: Editable fields pre-filled from shop data - // VI: Các trường có thể sửa, điền sẵn từ dữ liệu shop - private string _editName = ""; - private string _editDescription = ""; - private string _editPhone = ""; - private string _editEmail = ""; - - protected override async Task OnInitializedAsync() - { - IsLoading = true; - try - { - if (Guid.TryParse(Id, out var shopId)) - { - _shop = await DataService.GetShopByIdAsync(shopId); - if (_shop != null) - { - _editName = _shop.Name; - _editDescription = _shop.Description ?? ""; - _editPhone = _shop.Phone ?? ""; - _editEmail = _shop.Email ?? ""; - } - } - } - catch - { - _shop = null; - } - finally - { - IsLoading = false; - } - } - - private async Task SaveSettings() - { - if (_isSaving || _shop == null) return; - _isSaving = true; - _successMessage = null; - _errorMessage = null; - StateHasChanged(); - - var dto = new ShopUpdateDto - { - Name = _editName, - Description = _editDescription, - Phone = _editPhone, - Email = _editEmail - }; - - var (success, error) = await MerchantApi.UpdateShopAsync(_shop.Id, dto); - if (success) - { - _successMessage = "Đã lưu thành công!"; - // EN: Reload shop data to reflect changes - // VI: Tải lại dữ liệu shop để phản ánh thay đổi - _shop = await DataService.GetShopByIdAsync(_shop.Id); - } - else - { - _errorMessage = error ?? "Không thể lưu thay đổi"; - } - - _isSaving = false; - } - - private static string GetStatusLabel(string? status) => status?.ToLowerInvariant() switch - { - "published" or "active" => "Đang mở", - "draft" or "setup" => "Thiết lập", - "inactive" or "paused" => "Tạm dừng", - "closed" => "Đã đóng", - _ => status ?? "—" - }; - - private record PaymentMethod(string Name, string Icon, string Color, string Desc, bool Enabled); - private readonly PaymentMethod[] _paymentMethods = new[] - { - new PaymentMethod("Tiền mặt", "banknote", "#22C55E", "Thanh toán trực tiếp", true), - new PaymentMethod("Thẻ ngân hàng", "credit-card", "#3B82F6", "Visa, Mastercard, JCB", true), - new PaymentMethod("QR Code", "qr-code", "#8B5CF6", "VNPay, MoMo, ZaloPay", true), - new PaymentMethod("Chuyển khoản", "send", "#F59E0B", "Chuyển khoản ngân hàng", false), - new PaymentMethod("Thẻ quà tặng", "gift", "#EC4899", "Gift card & voucher", false), - }; -}