diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Cafe/CafeDesktop.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Cafe/CafeDesktop.razor index ee86c864..6c15649e 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Cafe/CafeDesktop.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Cafe/CafeDesktop.razor @@ -5,33 +5,49 @@ @page "/pos/cafe" @layout PosLayout @inherits PosBase +@inject WebClientTpos.Client.Services.PosDataService DataService @* ═══ PRODUCT PANEL ═══ *@
- @* EN: Category tabs / VI: Tab danh mục *@ -
- @foreach (var cat in _categories) - { - - } -
+ @if (_isLoading) + { +
+ Đang tải... +
+ } + else if (_loadError) + { +
+ Không thể tải dữ liệu +
+ } + else + { + @* EN: Category tabs / VI: Tab danh mục *@ +
+ @foreach (var cat in _categories) + { + + } +
- @* EN: Product grid / VI: Lưới sản phẩm *@ -
- @foreach (var product in FilteredProducts) - { -
-
- + @* EN: Product grid / VI: Lưới sản phẩm *@ +
+ @foreach (var product in FilteredProducts) + { +
+
+ +
+ @product.Name + @FormatPrice(product.Price)
- @product.Name - @FormatPrice(product.Price) -
- } -
+ } +
+ }
@* ═══ CART PANEL ═══ *@ @@ -71,29 +87,19 @@
@code { + // EN: Cafe shop ID / VI: ID cửa hàng cafe + private static readonly Guid CafeShopId = Guid.Parse("b0000001-0000-0000-0000-000000000001"); + + // EN: Loading state / VI: Trạng thái tải + private bool _isLoading = true; + private bool _loadError; + // EN: Categories / VI: Danh mục - private readonly string[] _categories = { "Tất cả", "Cà phê", "Trà", "Sinh tố", "Đồ ăn" }; + private string[] _categories = { "Tất cả" }; private string _selectedCategory = "Tất cả"; // EN: Product list / VI: Danh sách sản phẩm - private readonly List _products = new() - { - new("Cà phê sữa đá", 35_000, "Cà phê"), - new("Cà phê đen", 29_000, "Cà phê"), - new("Bạc xỉu", 39_000, "Cà phê"), - new("Espresso", 45_000, "Cà phê"), - new("Cappuccino", 55_000, "Cà phê"), - new("Latte", 55_000, "Cà phê"), - new("Trà đào", 45_000, "Trà"), - new("Trà vải", 45_000, "Trà"), - new("Trà sen vàng", 49_000, "Trà"), - new("Sinh tố bơ", 55_000, "Sinh tố"), - new("Sinh tố xoài", 49_000, "Sinh tố"), - new("Sinh tố dâu", 49_000, "Sinh tố"), - new("Bánh mì", 25_000, "Đồ ăn"), - new("Croissant", 35_000, "Đồ ăn"), - new("Cookie", 20_000, "Đồ ăn"), - }; + private List _products = new(); // EN: Cart items / VI: Mục giỏ hàng private readonly List _cartItems = new(); @@ -101,6 +107,42 @@ _selectedCategory == "Tất cả" ? _products : _products.Where(p => p.Category == _selectedCategory); private decimal CartTotal => _cartItems.Sum(i => i.Price * i.Qty); + protected override async Task OnInitializedAsync() + { + try + { + var productsTask = DataService.GetProductsAsync(CafeShopId); + var categoriesTask = DataService.GetCategoriesAsync(CafeShopId); + await Task.WhenAll(productsTask, categoriesTask); + + var apiProducts = await productsTask; + var apiCategories = await categoriesTask; + + _products = apiProducts.Select(p => new Product( + p.Name, + p.Price, + p.Category ?? "Khác" + )).ToList(); + + var catNames = apiCategories.Select(c => c.Name).ToList(); + if (catNames.Count > 0) + _categories = new[] { "Tất cả" }.Concat(catNames).ToArray(); + else + { + var productCats = _products.Select(p => p.Category).Distinct().ToList(); + _categories = new[] { "Tất cả" }.Concat(productCats).ToArray(); + } + } + catch + { + _loadError = true; + } + finally + { + _isLoading = false; + } + } + private void AddToCart(Product product) { var existing = _cartItems.FirstOrDefault(i => i.Name == product.Name); diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Karaoke/KaraokeDesktop.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Karaoke/KaraokeDesktop.razor index 2b93bdad..998ee465 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Karaoke/KaraokeDesktop.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Karaoke/KaraokeDesktop.razor @@ -1,6 +1,12 @@ @* EN: Karaoke POS Desktop — Room map grid + session panel for karaoke room management. + TODO: Replace mock room data with API call to FnB engine rooms endpoint + (e.g. DataService.GetTablesAsync with room-type filter) when the karaoke-specific + table/room schema is implemented in the FnB engine database. VI: POS Karaoke Desktop — Lưới sơ đồ phòng + panel phiên hát cho quản lý phòng karaoke. + TODO: Thay dữ liệu phòng giả bằng API call đến FnB engine rooms endpoint + (ví dụ DataService.GetTablesAsync với bộ lọc loại phòng) khi schema bàn/phòng + karaoke được triển khai trong cơ sở dữ liệu FnB engine. *@ @page "/pos/karaoke" @layout PosLayout diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantDesktop.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantDesktop.razor index 9a2c38d6..98847be9 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantDesktop.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Restaurant/RestaurantDesktop.razor @@ -5,35 +5,51 @@ @page "/pos/restaurant" @layout PosLayout @inherits PosBase +@inject WebClientTpos.Client.Services.PosDataService DataService
- @* ═══ SECTION TABS / TAB KHU VỰC ═══ *@ -
- @foreach (var section in _sections) - { - - } -
+ @if (_isLoading) + { +
+ Đang tải... +
+ } + else if (_loadError) + { +
+ Không thể tải dữ liệu +
+ } + else + { + @* ═══ SECTION TABS / TAB KHU VỰC ═══ *@ +
+ @foreach (var section in _sections) + { + + } +
- @* ═══ TABLE MAP GRID / LƯỚI SƠ ĐỒ BÀN ═══ *@ -
- @foreach (var table in FilteredTables) - { -
-
@table.Name
-
@table.Seats chỗ
-
- @GetStatusLabel(table.Status) + @* ═══ TABLE MAP GRID / LƯỚI SƠ ĐỒ BÀN ═══ *@ +
+ @foreach (var table in FilteredTables) + { +
+
@table.Name
+
@table.Seats chỗ
+
+ @GetStatusLabel(table.Status) +
-
- } -
+ } +
+ }
@* ═══ ORDER PANEL (RIGHT) / PANEL ĐẶT MÓN (PHẢI) ═══ *@ @@ -86,23 +102,22 @@
@code { + // EN: Restaurant shop ID / VI: ID cửa hàng nhà hàng + private static readonly Guid RestaurantShopId = Guid.Parse("b0000002-0000-0000-0000-000000000002"); + + // EN: Loading state / VI: Trạng thái tải + private bool _isLoading = true; + private bool _loadError; + // EN: Active section filter / VI: Bộ lọc khu vực private string _activeSection = "Tất cả"; - private readonly string[] _sections = { "Tất cả", "Trong nhà", "Ngoài trời", "VIP" }; + private string[] _sections = { "Tất cả" }; // EN: Selected table reference / VI: Bàn đang chọn private TableInfo? SelectedTable { get; set; } - // EN: Demo table data / VI: Dữ liệu bàn mẫu - private readonly List _tables = new() - { - new("T01","Bàn 1", 4, "available", "Trong nhà"), new("T02","Bàn 2", 2, "occupied", "Trong nhà"), - new("T03","Bàn 3", 6, "occupied", "Trong nhà"), new("T04","Bàn 4", 4, "reserved", "Trong nhà"), - new("T05","Bàn 5", 2, "available", "Trong nhà"), new("T06","Bàn 6", 8, "available", "VIP"), - new("T07","Bàn 7", 4, "occupied", "Ngoài trời"), new("T08","Bàn 8", 4, "available", "Ngoài trời"), - new("T09","Bàn 9", 10, "reserved", "VIP"), new("T10","Bàn 10", 2, "available", "Ngoài trời"), - new("T11","Bàn 11", 6, "occupied", "VIP"), new("T12","Bàn 12", 4, "available", "Trong nhà"), - }; + // EN: Table data from API / VI: Dữ liệu bàn từ API + private List _tables = new(); private IEnumerable FilteredTables => _activeSection == "Tất cả" ? _tables : _tables.Where(t => t.Section == _activeSection); @@ -114,6 +129,33 @@ new("Cơm tấm sườn", 65_000, 1), new("Trà đá", 10_000, 3), }; + protected override async Task OnInitializedAsync() + { + try + { + var apiTables = await DataService.GetTablesAsync(RestaurantShopId); + + _tables = apiTables.Select(t => new TableInfo( + t.Id.ToString(), + $"Bàn {t.TableNumber}", + t.Capacity, + t.Status ?? "available", + t.Zone ?? "Trong nhà" + )).ToList(); + + var zones = _tables.Select(t => t.Section).Distinct().ToList(); + _sections = new[] { "Tất cả" }.Concat(zones).ToArray(); + } + catch + { + _loadError = true; + } + finally + { + _isLoading = false; + } + } + private void SelectTable(TableInfo table) => SelectedTable = table; private static string GetStatusColor(string status) => status switch diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Spa/SpaDesktop.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Spa/SpaDesktop.razor index 795a5197..8d5760f3 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Spa/SpaDesktop.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Spa/SpaDesktop.razor @@ -5,36 +5,52 @@ @page "/pos/spa" @layout PosLayout @inherits PosBase +@inject WebClientTpos.Client.Services.PosDataService DataService @* ═══ SERVICE PANEL (LEFT) / PANEL DỊCH VỤ (TRÁI) ═══ *@
- @* EN: Category tabs / VI: Tab danh mục *@ -
- @foreach (var cat in _categories) - { - - } -
+ @if (_isLoading) + { +
+ Đang tải... +
+ } + else if (_loadError) + { +
+ Không thể tải dữ liệu +
+ } + else + { + @* EN: Category tabs / VI: Tab danh mục *@ +
+ @foreach (var cat in _categories) + { + + } +
- @* ═══ SERVICE GRID / LƯỚI DỊCH VỤ ═══ *@ -
- @foreach (var svc in FilteredServices) - { -
-
- + @* ═══ SERVICE GRID / LƯỚI DỊCH VỤ ═══ *@ +
+ @foreach (var svc in FilteredServices) + { +
+
+ +
+ @svc.Name + @FormatPrice(svc.Price) + + @svc.Duration phút +
- @svc.Name - @FormatPrice(svc.Price) - - @svc.Duration phút - -
- } -
+ } +
+ }
@* ═══ APPOINTMENT PANEL (RIGHT) / PANEL LỊCH HẸN (PHẢI) ═══ *@ @@ -110,8 +126,15 @@
@code { + // EN: Spa shop ID / VI: ID cửa hàng spa + private static readonly Guid SpaShopId = Guid.Parse("b0000004-0000-0000-0000-000000000004"); + + // EN: Loading state / VI: Trạng thái tải + private bool _isLoading = true; + private bool _loadError; + // EN: Categories / VI: Danh mục - private readonly string[] _categories = { "Tất cả", "Massage", "Facial", "Body", "Nail", "Hair" }; + private string[] _categories = { "Tất cả" }; private string _selectedCategory = "Tất cả"; // EN: Demo customer / VI: Khách hàng mẫu @@ -119,22 +142,8 @@ private string _customerPhone = "0901234567"; private string _customerTier = "Gold"; - // EN: Service list / VI: Danh sách dịch vụ - private readonly List _services = new() - { - new("Massage toàn thân", 500_000, 60, "Massage"), - new("Massage chân", 250_000, 45, "Massage"), - new("Massage đầu vai cổ", 300_000, 30, "Massage"), - new("Facial cơ bản", 350_000, 45, "Facial"), - new("Facial collagen", 600_000, 60, "Facial"), - new("Tắm trắng toàn thân", 800_000, 90, "Body"), - new("Tẩy tế bào chết", 400_000, 45, "Body"), - new("Sơn gel", 150_000, 30, "Nail"), - new("Nail art cao cấp", 300_000, 60, "Nail"), - new("Chăm sóc móng tay", 120_000, 30, "Nail"), - new("Gội đầu dưỡng sinh", 200_000, 40, "Hair"), - new("Ủ tóc phục hồi", 350_000, 45, "Hair"), - }; + // EN: Service list from API / VI: Danh sách dịch vụ từ API + private List _services = new(); // EN: Appointment items / VI: Mục lịch hẹn private readonly List _appointmentItems = new(); @@ -142,6 +151,32 @@ _selectedCategory == "Tất cả" ? _services : _services.Where(s => s.Category == _selectedCategory); private decimal AppointmentTotal => _appointmentItems.Sum(i => i.Price); + protected override async Task OnInitializedAsync() + { + try + { + var apiProducts = await DataService.GetProductsAsync(SpaShopId); + + _services = apiProducts.Select(p => new SpaService( + p.Name, + p.Price, + p.DurationMinutes ?? 60, + p.Category ?? "Khác" + )).ToList(); + + var cats = _services.Select(s => s.Category).Distinct().ToList(); + _categories = new[] { "Tất cả" }.Concat(cats).ToArray(); + } + catch + { + _loadError = true; + } + finally + { + _isLoading = false; + } + } + private void AddToAppointment(SpaService svc) { _appointmentItems.Add(new AppointmentItem(svc.Name, svc.Price, svc.Duration));