refactor(pos): replace hardcoded shop IDs with dynamic ShopId route parameter across all POS files

This commit is contained in:
Ho Ngoc Hai
2026-02-28 11:22:46 +07:00
parent 364ba541ea
commit 75bcff209b
88 changed files with 176 additions and 193 deletions

View File

@@ -372,7 +372,7 @@
</div>
<h2 style="font-size:22px;font-weight:700;margin:0 0 8px;color:var(--pos-text-primary, #FFFFFF);">POS Bán hàng</h2>
<p style="font-size:14px;color:var(--admin-text-tertiary);margin:0 0 24px;max-width:400px;margin-left:auto;margin-right:auto;">Mở giao diện bán hàng tại điểm để tạo đơn, thanh toán và in hóa đơn.</p>
<a href="/pos" class="admin-btn-primary" style="display:inline-flex;align-items:center;gap:8px;text-decoration:none;font-size:16px;padding:12px 28px;">
<a href="/pos/@ShopId/@(_posVertical)" class="admin-btn-primary" style="display:inline-flex;align-items:center;gap:8px;text-decoration:none;font-size:16px;padding:12px 28px;">
<i data-lucide="monitor" style="width:18px;height:18px;"></i>
Mở POS
</a>
@@ -460,6 +460,7 @@
private string _sectionIcon = "layout-dashboard";
private string _sectionDescription = "";
private string? _errorMessage;
private string _posVertical = "cafe";
private Guid? _shopGuid;
// ═══ DATA ═══
@@ -500,6 +501,7 @@
{
_shopName = shop.Name ?? "Cửa hàng";
_verticalLabel = ShopSidebarConfig.GetVerticalLabel(shop.Category);
_posVertical = MapCategoryToVertical(shop.Category);
Layout?.SetShopContext(ShopId, _shopName, shop.Category);
}
}
@@ -598,4 +600,18 @@
if (hex.Length != 6) return "0,0,0";
return $"{Convert.ToInt32(hex[..2], 16)},{Convert.ToInt32(hex[2..4], 16)},{Convert.ToInt32(hex[4..], 16)}";
}
/// <summary>
/// EN: Map shop category to POS route segment.
/// VI: Chuyển đổi danh mục cửa hàng thành segment POS route.
/// </summary>
private static string MapCategoryToVertical(string? category) => (category?.ToLowerInvariant()) switch
{
"cafe" or "coffee" => "cafe",
"restaurant" or "nhahang" => "restaurant",
"karaoke" => "karaoke",
"spa" or "beauty" => "spa",
"retail" or "banle" => "retail",
_ => "cafe"
};
}

View File

@@ -2,7 +2,7 @@
EN: Café POS Desktop — 3-column layout: categories, product grid, cart.
VI: POS Café Desktop — Bố cục 3 cột: danh mục, lưới sản phẩm, giỏ hàng.
*@
@page "/pos/cafe"
@page "/pos/{ShopId:guid}/cafe"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -87,8 +87,6 @@
</div>
@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;
@@ -111,8 +109,8 @@
{
try
{
var productsTask = DataService.GetProductsAsync(CafeShopId);
var categoriesTask = DataService.GetCategoriesAsync(CafeShopId);
var productsTask = DataService.GetProductsAsync(ShopId);
var categoriesTask = DataService.GetCategoriesAsync(ShopId);
await Task.WhenAll(productsTask, categoriesTask);
var apiProducts = await productsTask;

View File

@@ -2,7 +2,7 @@
EN: Café POS Mobile — Single column: categories, product grid, floating cart button.
VI: POS Café Mobile — Một cột: danh mục, lưới sản phẩm, nút giỏ hàng nổi.
*@
@page "/pos/cafe/mobile"
@page "/pos/{ShopId:guid}/cafe/mobile"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -108,8 +108,6 @@
</div>
@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;
@@ -133,8 +131,8 @@
{
try
{
var productsTask = DataService.GetProductsAsync(CafeShopId);
var categoriesTask = DataService.GetCategoriesAsync(CafeShopId);
var productsTask = DataService.GetProductsAsync(ShopId);
var categoriesTask = DataService.GetCategoriesAsync(ShopId);
await Task.WhenAll(productsTask, categoriesTask);
var apiProducts = await productsTask;

View File

@@ -2,7 +2,7 @@
EN: Café POS Tablet — 2-column layout: product grid + cart sidebar, touch-friendly.
VI: POS Café Tablet — Bố cục 2 cột: lưới sản phẩm + giỏ hàng bên, thân thiện cảm ứng.
*@
@page "/pos/cafe/tablet"
@page "/pos/{ShopId:guid}/cafe/tablet"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -88,8 +88,6 @@
</div>
@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;
@@ -112,8 +110,8 @@
{
try
{
var productsTask = DataService.GetProductsAsync(CafeShopId);
var categoriesTask = DataService.GetCategoriesAsync(CafeShopId);
var productsTask = DataService.GetProductsAsync(ShopId);
var categoriesTask = DataService.GetCategoriesAsync(ShopId);
await Task.WhenAll(productsTask, categoriesTask);
var apiProducts = await productsTask;

View File

@@ -2,7 +2,7 @@
EN: Barista Queue — Kanban-style order queue: New / In Progress / Ready columns.
VI: Hàng đợi Barista — Bảng đơn hàng kiểu Kanban: Mới / Đang pha / Sẵn sàng.
*@
@page "/pos/cafe/barista-queue"
@page "/pos/{ShopId:guid}/cafe/barista-queue"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Cafe Journey — End-to-end café workflow tracker: Đặt món → Thanh toán → Pha chế → Phục vụ → Hoàn tất.
VI: Hành trình Café — Theo dõi quy trình từ đầu đến cuối: Đặt món → Thanh toán → Pha chế → Phục vụ → Hoàn tất.
*@
@page "/pos/cafe/cafe-journey"
@page "/pos/{ShopId:guid}/cafe/cafe-journey"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Customer Display — Customer-facing screen: current order, total, branding.
VI: Màn hình khách hàng — Hiển thị đơn hàng, tổng tiền, thương hiệu.
*@
@page "/pos/cafe/customer-display"
@page "/pos/{ShopId:guid}/cafe/customer-display"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Daily Report — End-of-day summary: revenue, orders, popular items, payment breakdown.
VI: Báo cáo ngày — Tổng kết cuối ngày: doanh thu, đơn hàng, món phổ biến, phân tích thanh toán.
*@
@page "/pos/cafe/daily-report"
@page "/pos/{ShopId:guid}/cafe/daily-report"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Loyalty Stamp — Customer stamp card: points, stamps grid, reward progress.
VI: Thẻ tích điểm — Thẻ khách hàng: điểm, lưới tem, tiến trình thưởng.
*@
@page "/pos/cafe/loyalty-stamp"
@page "/pos/{ShopId:guid}/cafe/loyalty-stamp"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Menu Management — Quick menu: toggle availability, sold-out marking, price override.
VI: Quản lý menu — Menu nhanh: bật/tắt khả dụng, đánh dấu hết hàng, ghi đè giá.
*@
@page "/pos/cafe/menu-management"
@page "/pos/{ShopId:guid}/cafe/menu-management"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -112,8 +112,6 @@
</div>
@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;
@@ -132,8 +130,8 @@
{
try
{
var productsTask = DataService.GetProductsAsync(CafeShopId);
var categoriesTask = DataService.GetCategoriesAsync(CafeShopId);
var productsTask = DataService.GetProductsAsync(ShopId);
var categoriesTask = DataService.GetCategoriesAsync(ShopId);
await Task.WhenAll(productsTask, categoriesTask);
var apiProducts = await productsTask;

View File

@@ -2,7 +2,7 @@
EN: Milk Foam Options — Milk type, foam level, temperature, extras for drink customization.
VI: Tùy chọn sữa & foam — Loại sữa, mức foam, nhiệt độ, thêm topping cho đồ uống.
*@
@page "/pos/cafe/milk-foam-options"
@page "/pos/{ShopId:guid}/cafe/milk-foam-options"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Order Customize — Drink customization: size, sugar, ice, toppings.
VI: Tùy chỉnh đơn hàng — Tùy chỉnh đồ uống: size, đường, đá, topping.
*@
@page "/pos/cafe/order-customize"
@page "/pos/{ShopId:guid}/cafe/order-customize"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Queue Display — Public-facing queue board: preparing list, ready list, large order numbers.
VI: Bảng hiển thị hàng đợi — Bảng công khai: danh sách đang pha, sẵn sàng, số đơn lớn.
*@
@page "/pos/cafe/queue-display"
@page "/pos/{ShopId:guid}/cafe/queue-display"
@layout PosLayout
@inherits PosBase

View File

@@ -8,7 +8,7 @@
(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"
@page "/pos/{ShopId:guid}/karaoke"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -147,8 +147,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -181,7 +179,7 @@
{
try
{
var tables = await DataService.GetTablesAsync(KaraokeShopId);
var tables = await DataService.GetTablesAsync(ShopId);
_rooms = tables.Select(t => new RoomInfo(
t.Id.ToString(),

View File

@@ -2,7 +2,7 @@
EN: Karaoke POS Mobile — Single column room list, tap to open room session.
VI: POS Karaoke Mobile — Danh sách phòng cột đơn, nhấn để mở phiên phòng.
*@
@page "/pos/karaoke/mobile"
@page "/pos/{ShopId:guid}/karaoke/mobile"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -98,8 +98,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -119,7 +117,7 @@
{
try
{
var tables = await DataService.GetTablesAsync(KaraokeShopId);
var tables = await DataService.GetTablesAsync(ShopId);
_rooms = tables.Select(t => new RoomInfo(
t.Id.ToString(),

View File

@@ -2,7 +2,7 @@
EN: Karaoke POS Tablet — Touch-optimized room map + session sidebar.
VI: POS Karaoke Tablet — Sơ đồ phòng tối ưu cảm ứng + thanh phiên bên cạnh.
*@
@page "/pos/karaoke/tablet"
@page "/pos/{ShopId:guid}/karaoke/tablet"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -139,8 +139,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -168,7 +166,7 @@
{
try
{
var tables = await DataService.GetTablesAsync(KaraokeShopId);
var tables = await DataService.GetTablesAsync(ShopId);
_rooms = tables.Select(t => new RoomInfo(
t.Id.ToString(),

View File

@@ -2,7 +2,7 @@
EN: Karaoke Happy Hour — Time-based pricing display, active promotions, countdown timer.
VI: Happy Hour Karaoke — Hiển thị giá theo giờ, khuyến mãi đang áp dụng, đồng hồ đếm ngược.
*@
@page "/pos/karaoke/happy-hour"
@page "/pos/{ShopId:guid}/karaoke/happy-hour"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Karaoke Journey — End-to-end session workflow tracker with 6 steps from reception to payment.
VI: Hành trình Karaoke — Theo dõi quy trình phiên từ đón khách đến thanh toán qua 6 bước.
*@
@page "/pos/karaoke/karaoke-journey"
@page "/pos/{ShopId:guid}/karaoke/karaoke-journey"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Karaoke Member Card — Member lookup, tier info, points, history, apply discount.
VI: Thẻ thành viên Karaoke — Tra cứu thành viên, hạng, điểm, lịch sử, áp dụng giảm giá.
*@
@page "/pos/karaoke/member-card"
@page "/pos/{ShopId:guid}/karaoke/member-card"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Karaoke F&B Order — Food & beverage ordering for active room session.
VI: Gọi F&B Karaoke — Đặt đồ ăn thức uống cho phiên phòng đang hoạt động.
*@
@page "/pos/karaoke/order-fnb"
@page "/pos/{ShopId:guid}/karaoke/order-fnb"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -113,8 +113,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -137,8 +135,8 @@
{
try
{
var productsTask = DataService.GetProductsAsync(KaraokeShopId);
var categoriesTask = DataService.GetCategoriesAsync(KaraokeShopId);
var productsTask = DataService.GetProductsAsync(ShopId);
var categoriesTask = DataService.GetCategoriesAsync(ShopId);
await Task.WhenAll(productsTask, categoriesTask);
var apiProducts = await productsTask;

View File

@@ -2,7 +2,7 @@
EN: Karaoke Peak Warning — Peak hours pricing comparison, room type multipliers, cost estimator.
VI: Cảnh báo giờ cao điểm Karaoke — So sánh giá giờ cao điểm, hệ số phòng, ước tính chi phí.
*@
@page "/pos/karaoke/peak-warning"
@page "/pos/{ShopId:guid}/karaoke/peak-warning"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Karaoke Room Extend — Extension dialog with time options, new end time preview, peak warning.
VI: Gia hạn phòng Karaoke — Dialog gia hạn với tùy chọn thời gian, xem trước giờ kết thúc, cảnh báo giờ cao điểm.
*@
@page "/pos/karaoke/room-extend"
@page "/pos/{ShopId:guid}/karaoke/room-extend"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Karaoke Room Map — Floor plan with rooms by floor/zone, color-coded status.
VI: Sơ đồ phòng Karaoke — Mặt bằng phòng theo tầng/khu, mã màu trạng thái.
*@
@page "/pos/karaoke/room-map"
@page "/pos/{ShopId:guid}/karaoke/room-map"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -109,8 +109,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -128,7 +126,7 @@
{
try
{
var tables = await DataService.GetTablesAsync(KaraokeShopId);
var tables = await DataService.GetTablesAsync(ShopId);
_rooms = tables.Select(t => new RoomInfo(
t.Id.ToString(),

View File

@@ -2,7 +2,7 @@
EN: Karaoke Room Reset — Cleanup checklist after session ends, progress tracking, staff assignment.
VI: Reset phòng Karaoke — Danh sách dọn dẹp sau phiên, theo dõi tiến độ, phân công nhân viên.
*@
@page "/pos/karaoke/room-reset"
@page "/pos/{ShopId:guid}/karaoke/room-reset"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Karaoke Room Select — Filter by type/capacity, available rooms, price per hour, start session.
VI: Chọn phòng Karaoke — Lọc theo loại/sức chứa, phòng trống, giá/giờ, bắt đầu phiên.
*@
@page "/pos/karaoke/room-select"
@page "/pos/{ShopId:guid}/karaoke/room-select"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -166,8 +166,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -189,7 +187,7 @@
{
try
{
var tables = await DataService.GetTablesAsync(KaraokeShopId);
var tables = await DataService.GetTablesAsync(ShopId);
_rooms = tables
.Where(t => t.Status == "available")

View File

@@ -2,7 +2,7 @@
EN: Karaoke Room Session — Active room timer, F&B orders, extend/end session, total.
VI: Phiên phòng Karaoke — Đồng hồ phòng, đơn F&B, gia hạn/kết thúc, tổng cộng.
*@
@page "/pos/karaoke/room-session"
@page "/pos/{ShopId:guid}/karaoke/room-session"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -161,8 +161,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -179,7 +177,7 @@
{
try
{
var products = await DataService.GetProductsAsync(KaraokeShopId);
var products = await DataService.GetProductsAsync(ShopId);
_fnbItems = products.Take(6).Select(p => new FnbItem(p.Name, p.Price, 1)).ToList();
}

View File

@@ -2,7 +2,7 @@
EN: Karaoke Service Display — Room service call queue, request type, timestamp, status.
VI: Hiển thị yêu cầu phục vụ Karaoke — Hàng đợi gọi phục vụ phòng, loại yêu cầu, thời gian, trạng thái.
*@
@page "/pos/karaoke/service-display"
@page "/pos/{ShopId:guid}/karaoke/service-display"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -139,8 +139,6 @@
</div>
@code {
// EN: Karaoke shop ID / VI: ID cửa hàng karaoke
private static readonly Guid KaraokeShopId = Guid.Parse("b0000003-0000-0000-0000-000000000003");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -170,7 +168,7 @@
{
try
{
var tables = await DataService.GetTablesAsync(KaraokeShopId);
var tables = await DataService.GetTablesAsync(ShopId);
_roomNames = tables.Select(t => t.TableNumber).ToList();
}
catch

View File

@@ -4,11 +4,19 @@ namespace WebClientTpos.Client.Pages.Pos;
/// <summary>
/// EN: Base class for all POS pages — shift state, offline detection, cart management.
/// Provides ShopId from route parameter so all POS pages use real shop data.
/// VI: Lớp cơ sở cho tất cả trang POS — trạng thái ca, phát hiện offline, quản lý giỏ hàng.
/// Cung cấp ShopId từ route parameter để tất cả trang POS dùng dữ liệu shop thật.
/// </summary>
public abstract class PosBase : ComponentBase
{
[Inject] protected NavigationManager NavigationManager { get; set; } = default!;
/// <summary>
/// EN: Shop ID from route — injected into every POS page.
/// VI: ID cửa hàng từ route — inject vào mọi trang POS.
/// </summary>
[Parameter] public Guid ShopId { get; set; }
/// <summary>
/// EN: Whether POS is in offline mode.
@@ -50,11 +58,11 @@ public abstract class PosBase : ComponentBase
}
/// <summary>
/// EN: Navigate to POS sub-page.
/// VI: Điều hướng đến trang con POS.
/// EN: Navigate to POS sub-page, preserving the current ShopId in the route.
/// VI: Điều hướng đến trang con POS, giữ ShopId hiện tại trong route.
/// </summary>
protected void NavigateTo(string path)
{
NavigationManager.NavigateTo($"/pos/{path}");
NavigationManager.NavigateTo($"/pos/{ShopId}/{path}");
}
}

View File

@@ -2,7 +2,7 @@
EN: Restaurant POS Desktop — Table map grid + order panel for dine-in service.
VI: POS Nhà hàng Desktop — Lưới sơ đồ bàn + panel đặt món cho phục vụ tại chỗ.
*@
@page "/pos/restaurant"
@page "/pos/{ShopId:guid}/restaurant"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -102,8 +102,6 @@
</div>
@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;
@@ -133,7 +131,7 @@
{
try
{
var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
var apiTables = await DataService.GetTablesAsync(ShopId);
_tables = apiTables.Select(t => new TableInfo(
t.Id.ToString(),

View File

@@ -2,7 +2,7 @@
EN: Restaurant POS Mobile — Single-column table list view, tap to order.
VI: POS Nhà hàng Mobile — Danh sách bàn cột đơn, chạm để đặt món.
*@
@page "/pos/restaurant/mobile"
@page "/pos/{ShopId:guid}/restaurant/mobile"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -92,8 +92,6 @@
</div>
@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;
@@ -113,7 +111,7 @@
{
try
{
var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
var apiTables = await DataService.GetTablesAsync(ShopId);
_tables = apiTables.Select(t => new MobileTable(
int.TryParse(t.TableNumber, out var num) ? num : 0,

View File

@@ -2,7 +2,7 @@
EN: Restaurant POS Tablet — Touch-optimized table map with order sidebar.
VI: POS Nhà hàng Tablet — Sơ đồ bàn tối ưu cảm ứng với sidebar đặt món.
*@
@page "/pos/restaurant/tablet"
@page "/pos/{ShopId:guid}/restaurant/tablet"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -101,8 +101,6 @@
</div>
@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;
@@ -132,7 +130,7 @@
{
try
{
var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
var apiTables = await DataService.GetTablesAsync(ShopId);
_tables = apiTables.Select(t => new TableInfo(
t.Id.ToString(),

View File

@@ -2,7 +2,7 @@
EN: Allergen Warning — Allergen alert display with toggles, severity levels, customer profile.
VI: Cảnh báo dị ứng — Hiển thị cảnh báo dị ứng với toggle, mức độ nghiêm trọng, hồ sơ khách.
*@
@page "/pos/restaurant/allergen-warning"
@page "/pos/{ShopId:guid}/restaurant/allergen-warning"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Course Timing — Multi-course meal timing management with fire buttons and timeline.
VI: Quản lý thời gian course — Quản lý thời gian tiệc nhiều món với nút fire và timeline.
*@
@page "/pos/restaurant/course-timing"
@page "/pos/{ShopId:guid}/restaurant/course-timing"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: End-of-Day Report — Covers, revenue, avg check, tip total, by-section breakdown.
VI: Báo cáo cuối ngày — Lượt khách, doanh thu, hóa đơn TB, tổng tip, phân tích theo khu vực.
*@
@page "/pos/restaurant/eod-report"
@page "/pos/{ShopId:guid}/restaurant/eod-report"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Kitchen Display System — Order tickets by status with timer and bump button.
VI: Hệ thống hiển thị bếp — Phiếu đơn theo trạng thái với đồng hồ và nút hoàn thành.
*@
@page "/pos/restaurant/kitchen-display"
@page "/pos/{ShopId:guid}/restaurant/kitchen-display"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -110,8 +110,6 @@
</div>
@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;
@@ -139,7 +137,7 @@
{
// EN: Preload tables for reference — kitchen_tickets API not yet available
// VI: Tải trước bàn để tham chiếu — API kitchen_tickets chưa có
await DataService.GetTablesAsync(RestaurantShopId);
await DataService.GetTablesAsync(ShopId);
}
catch
{

View File

@@ -2,7 +2,7 @@
EN: Order History — Today's orders with table, items, total, payment method, time, server name.
VI: Lịch sử đơn hàng — Đơn hàng hôm nay với bàn, món, tổng, PTTT, giờ, tên PV.
*@
@page "/pos/restaurant/order-history"
@page "/pos/{ShopId:guid}/restaurant/order-history"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -109,8 +109,6 @@
</div>
@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;
@@ -148,7 +146,7 @@
{
// EN: Preload tables for reference — orders API not yet available
// VI: Tải trước bàn để tham chiếu — API orders chưa có
await DataService.GetTablesAsync(RestaurantShopId);
await DataService.GetTablesAsync(ShopId);
}
catch
{

View File

@@ -2,7 +2,7 @@
EN: Order Note — Special notes interface with quick chips, custom textarea, kitchen priority.
VI: Ghi chú đơn hàng — Giao diện ghi chú đặc biệt với chip nhanh, textarea tùy chỉnh, ưu tiên bếp.
*@
@page "/pos/restaurant/order-note"
@page "/pos/{ShopId:guid}/restaurant/order-note"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Reservation Management — Date picker, time slots, guest info, table assignment, status.
VI: Quản lý đặt bàn — Chọn ngày, khung giờ, thông tin khách, gán bàn, trạng thái.
*@
@page "/pos/restaurant/reservation"
@page "/pos/{ShopId:guid}/restaurant/reservation"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Restaurant Journey — End-to-end restaurant workflow: Đón khách → Chọn bàn → Đặt món → Bếp → Tiếp tục → Thanh toán → Hoàn tất.
VI: Hành trình nhà hàng — Quy trình từ đầu đến cuối: Đón khách → Chọn bàn → Đặt món → Bếp → Tiếp tục → Thanh toán → Hoàn tất.
*@
@page "/pos/restaurant/restaurant-journey"
@page "/pos/{ShopId:guid}/restaurant/restaurant-journey"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Restaurant Menu Management — Category tabs, item grid, edit mode, quick actions, stats.
VI: Quản lý thực đơn nhà hàng — Tab danh mục, lưới món, chế độ chỉnh sửa, thao tác nhanh, thống kê.
*@
@page "/pos/restaurant/menu-management"
@page "/pos/{ShopId:guid}/restaurant/menu-management"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -120,8 +120,6 @@
</div>
@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;
@@ -142,7 +140,7 @@
{
try
{
var products = await DataService.GetProductsAsync(RestaurantShopId);
var products = await DataService.GetProductsAsync(ShopId);
_menuItems = products.Select(p => new RestMenuItem(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Table Detail — Bill preview with items, subtotal, service charge, VAT, total, split bill.
VI: Chi tiết bàn — Xem hóa đơn với danh sách món, tạm tính, phí dịch vụ, VAT, tổng, tách hóa đơn.
*@
@page "/pos/restaurant/table-detail"
@page "/pos/{ShopId:guid}/restaurant/table-detail"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Full Table Map — Drag arrangement, sections (Indoor/Outdoor/VIP), merge/split tables.
VI: Sơ đồ bàn đầy đủ — Kéo thả sắp xếp, khu vực (Trong nhà/Ngoài trời/VIP), gộp/tách bàn.
*@
@page "/pos/restaurant/table-map"
@page "/pos/{ShopId:guid}/restaurant/table-map"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -88,8 +88,6 @@
</div>
@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;
@@ -109,7 +107,7 @@
{
try
{
var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
var apiTables = await DataService.GetTablesAsync(ShopId);
_tables = apiTables.Select(t => new MapTable(
t.Id.ToString(),

View File

@@ -2,7 +2,7 @@
EN: Table Merge/Split — Merge multiple tables or split a table with active order.
VI: Ghép/Tách bàn — Ghép nhiều bàn lại hoặc tách bàn có đơn đang hoạt động.
*@
@page "/pos/restaurant/table-merge-split"
@page "/pos/{ShopId:guid}/restaurant/table-merge-split"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -171,8 +171,6 @@
</div>
@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;
@@ -190,7 +188,7 @@
{
try
{
var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
var apiTables = await DataService.GetTablesAsync(ShopId);
_mergeTables = apiTables
.Select(t => new MergeTable(

View File

@@ -2,7 +2,7 @@
EN: Table Select — Quick table selection for seating guests with capacity matching.
VI: Chọn bàn nhanh — Chọn bàn nhanh cho khách với kiểm tra sức chứa.
*@
@page "/pos/restaurant/table-select"
@page "/pos/{ShopId:guid}/restaurant/table-select"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -133,8 +133,6 @@
</div>
@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;
@@ -155,7 +153,7 @@
{
try
{
var apiTables = await DataService.GetTablesAsync(RestaurantShopId);
var apiTables = await DataService.GetTablesAsync(ShopId);
_availableTables = apiTables
.Where(t => (t.Status ?? "available") == "available")

View File

@@ -2,7 +2,7 @@
EN: Waiter Pad — Order taking by course with special requests, send to kitchen.
VI: Pad Phục vụ — Gọi món theo course với yêu cầu đặc biệt, gửi bếp.
*@
@page "/pos/restaurant/waiter-pad"
@page "/pos/{ShopId:guid}/restaurant/waiter-pad"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -104,8 +104,6 @@
</div>
@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;
@@ -125,8 +123,8 @@
{
try
{
var products = await DataService.GetProductsAsync(RestaurantShopId);
var categories = await DataService.GetCategoriesAsync(RestaurantShopId);
var products = await DataService.GetProductsAsync(ShopId);
var categories = await DataService.GetCategoriesAsync(ShopId);
var categoryMap = categories.ToDictionary(c => c.Id, c => c.Name);

View File

@@ -2,7 +2,7 @@
EN: Retail POS Desktop — Left panel: category tabs + product grid with barcode input. Right panel: cart/bill.
VI: POS Bán lẻ Desktop — Panel trái: tab danh mục + lưới sản phẩm với quét mã vạch. Panel phải: giỏ hàng.
*@
@page "/pos/retail"
@page "/pos/{ShopId:guid}/retail"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -114,9 +114,6 @@
</div>
@code {
// EN: Retail shop ID (using cafe shop for now) / VI: ID cửa hàng bán lẻ (dùng tạm shop cafe)
private static readonly Guid RetailShopId = Guid.Parse("b0000001-0000-0000-0000-000000000001");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
private bool _loadError;
@@ -139,7 +136,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(RetailShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
_products = apiProducts.Select(p => new Product(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Retail POS Mobile — Single column, floating cart button, bottom sheet cart.
VI: POS Bán lẻ Mobile — Một cột, nút giỏ hàng nổi, giỏ hàng dạng sheet dưới.
*@
@page "/pos/retail/mobile"
@page "/pos/{ShopId:guid}/retail/mobile"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -118,9 +118,6 @@
</div>
@code {
// EN: Retail shop ID (using cafe shop for now) / VI: ID cửa hàng bán lẻ (dùng tạm shop cafe)
private static readonly Guid RetailShopId = Guid.Parse("b0000001-0000-0000-0000-000000000001");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
private bool _loadError;
@@ -143,7 +140,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(RetailShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
_products = apiProducts.Select(p => new Product(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Retail POS Tablet — Touch-optimized 2-column: products + cart sidebar (340px), larger elements.
VI: POS Bán lẻ Tablet — 2 cột tối ưu cảm ứng: sản phẩm + giỏ hàng bên (340px), phần tử lớn hơn.
*@
@page "/pos/retail/tablet"
@page "/pos/{ShopId:guid}/retail/tablet"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -112,8 +112,6 @@
</div>
@code {
// EN: Retail shop ID (using cafe shop for now) / VI: ID cửa hàng bán lẻ (dùng tạm shop cafe)
private static readonly Guid RetailShopId = Guid.Parse("b0000001-0000-0000-0000-000000000001");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
@@ -136,7 +134,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(RetailShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
_products = apiProducts.Select(p => new Product(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Product Search — Search by name, SKU, barcode with filters. Add to cart from results.
VI: Tìm kiếm sản phẩm — Tìm theo tên, SKU, mã vạch với bộ lọc. Thêm vào giỏ từ kết quả.
*@
@page "/pos/retail/product-search"
@page "/pos/{ShopId:guid}/retail/product-search"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -125,9 +125,6 @@
</div>
@code {
// EN: Retail shop ID (using cafe shop for now) / VI: ID cửa hàng bán lẻ (dùng tạm shop cafe)
private static readonly Guid RetailShopId = Guid.Parse("b0000001-0000-0000-0000-000000000001");
// EN: Loading state / VI: Trạng thái tải
private bool _isLoading = true;
private bool _loadError;
@@ -146,7 +143,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(RetailShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
_products = apiProducts.Select(p => new Product(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Returns & Exchanges — Receipt lookup, original order items, select returns, refund method, confirm.
VI: Đổi trả hàng — Tra cứu hóa đơn, món gốc, chọn trả, phương thức hoàn tiền, xác nhận.
*@
@page "/pos/retail/return-exchange"
@page "/pos/{ShopId:guid}/retail/return-exchange"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Stock Check — Product search/scan, stock across branches, recent movements, reorder suggestion.
VI: Kiểm kho — Tìm/quét sản phẩm, tồn kho theo chi nhánh, biến động gần đây, gợi ý đặt hàng.
*@
@page "/pos/retail/stock-check"
@page "/pos/{ShopId:guid}/retail/stock-check"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Cancel Order Confirmation — Order summary, reason dropdown, notes, refund warning, cancel/keep buttons.
VI: Xác nhận hủy đơn — Tổng quan đơn, lý do hủy, ghi chú, cảnh báo hoàn tiền, nút hủy/giữ đơn.
*@
@page "/pos/dialog/order-cancel"
@page "/pos/{ShopId:guid}/dialog/order-cancel"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Edit Existing Order — Editable item list, quantity controls, add items, discount, notes, recalculated total.
VI: Chỉnh sửa đơn hàng — Danh sách món chỉnh sửa, điều khiển số lượng, thêm món, giảm giá, ghi chú, tổng tính lại.
*@
@page "/pos/dialog/order-edit"
@page "/pos/{ShopId:guid}/dialog/order-edit"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Price Check — Barcode/SKU input, large price display, product details, promotions, price history.
VI: Kiểm tra giá — Nhập mã vạch/SKU, hiển thị giá lớn, chi tiết sản phẩm, khuyến mãi, lịch sử giá.
*@
@page "/pos/dialog/price-check"
@page "/pos/{ShopId:guid}/dialog/price-check"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Split Bill — Equal split, by-item split, custom split modes for shared bills.
VI: Tách hóa đơn — Chia đều, chia theo món, chia tùy chỉnh cho hóa đơn chung.
*@
@page "/pos/dialog/split-bill"
@page "/pos/{ShopId:guid}/dialog/split-bill"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Quick Stock-In Dialog — Product search, qty, supplier, unit cost, lot, expiry, notes, recent log.
VI: Nhập kho nhanh — Tìm sản phẩm, SL, nhà cung cấp, giá nhập, lô, hạn dùng, ghi chú, lịch sử gần đây.
*@
@page "/pos/dialog/stock-in"
@page "/pos/{ShopId:guid}/dialog/stock-in"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Stock-Out Dialog — Product search, current stock, remove qty, reason, authorization, notes.
VI: Xuất kho — Tìm sản phẩm, tồn kho hiện tại, SL xuất, lý do, xác nhận nhân viên, ghi chú.
*@
@page "/pos/dialog/stock-out"
@page "/pos/{ShopId:guid}/dialog/stock-out"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Stock Transfer — Transfer products between branches with product list, qty, delivery note.
VI: Chuyển kho — Chuyển sản phẩm giữa chi nhánh với danh sách, SL, phiếu giao hàng.
*@
@page "/pos/dialog/stock-transfer"
@page "/pos/{ShopId:guid}/dialog/stock-transfer"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Void / Refund Dialog — Order lookup, void vs refund selection, reason, manager PIN, confirm.
VI: Hủy / Hoàn tiền — Tra cứu đơn hàng, chọn hủy hay hoàn tiền, lý do, mã PIN quản lý, xác nhận.
*@
@page "/pos/dialog/void-refund"
@page "/pos/{ShopId:guid}/dialog/void-refund"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Cash Drawer — Denomination breakdown, quick count with +/- buttons, expected vs actual totals, variance.
VI: Quản lý ngăn kéo tiền — Bảng mệnh giá, đếm nhanh +/-, so sánh dự kiến/thực tế, chênh lệch.
*@
@page "/pos/operations/cash-drawer"
@page "/pos/{ShopId:guid}/operations/cash-drawer"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Staff Clock In/Out — Real-time clock, staff info, toggle clock button, today's log.
VI: Chấm công nhân viên — Đồng hồ thời gian thực, thông tin NV, nút chấm công, nhật ký hôm nay.
*@
@page "/pos/operations/clock-in-out"
@page "/pos/{ShopId:guid}/operations/clock-in-out"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Pending Orders — Active orders list with status filters, table/customer, items, elapsed time, quick actions.
VI: Đơn hàng đang chờ — Danh sách đơn đang xử lý với bộ lọc trạng thái, bàn/khách, món, thời gian, thao tác nhanh.
*@
@page "/pos/operations/pending-orders"
@page "/pos/{ShopId:guid}/operations/pending-orders"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Quick Sale — Numpad amount entry, category quick buttons, note field, pay button.
VI: Bán nhanh — Bàn phím số nhập tiền, nút danh mục nhanh, ghi chú, nút thanh toán.
*@
@page "/pos/operations/quick-sale"
@page "/pos/{ShopId:guid}/operations/quick-sale"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Shift Management — Current shift info, opening cash, quick actions, shift summary.
VI: Quản lý ca — Thông tin ca hiện tại, tiền mở ca, thao tác nhanh, tổng kết ca.
*@
@page "/pos/operations/shift"
@page "/pos/{ShopId:guid}/operations/shift"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Bank Transfer — Bank account info, reference code, transfer verification.
VI: Chuyển khoản ngân hàng — Thông tin tài khoản, mã tham chiếu, xác minh chuyển khoản.
*@
@page "/pos/payment/bank-transfer"
@page "/pos/{ShopId:guid}/payment/bank-transfer"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Card Payment — Card reader status, tap/swipe/insert instructions.
VI: Thanh toán thẻ — Trạng thái đầu đọc thẻ, hướng dẫn chạm/quẹt/cắm.
*@
@page "/pos/payment/card"
@page "/pos/{ShopId:guid}/payment/card"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Cash Payment — Cash payment with quick amount buttons and change calculation.
VI: Thanh toán tiền mặt — Nút số tiền nhanh và tính tiền thối.
*@
@page "/pos/payment/cash"
@page "/pos/{ShopId:guid}/payment/cash"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Gift Card Payment — Gift card code input, balance lookup, apply payment.
VI: Thanh toán thẻ quà tặng — Nhập mã thẻ, tra cứu số dư, áp dụng thanh toán.
*@
@page "/pos/payment/gift-card"
@page "/pos/{ShopId:guid}/payment/gift-card"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Payment Method Select — Choose payment method: Cash, Card, QR Code, Gift Card.
VI: Chọn phương thức thanh toán — Tiền mặt, Thẻ, Mã QR, Thẻ quà tặng.
*@
@page "/pos/payment/method-select"
@page "/pos/{ShopId:guid}/payment/method-select"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Partial Payment — Split payment across multiple methods.
VI: Thanh toán kết hợp — Chia thanh toán qua nhiều phương thức.
*@
@page "/pos/payment/partial"
@page "/pos/{ShopId:guid}/payment/partial"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Payment Pending — Processing animation, order total, payment method info.
VI: Đang xử lý thanh toán — Hiệu ứng xử lý, tổng đơn hàng, thông tin phương thức.
*@
@page "/pos/payment/pending"
@page "/pos/{ShopId:guid}/payment/pending"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Payment Success — Success animation, transaction details, print/new order buttons.
VI: Thanh toán thành công — Hiệu ứng thành công, chi tiết giao dịch, nút in/đơn mới.
*@
@page "/pos/payment/success"
@page "/pos/{ShopId:guid}/payment/success"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: QR Payment — QR code display with provider tabs, timer countdown.
VI: Thanh toán QR — Hiển thị mã QR với tab nhà cung cấp, đếm ngược.
*@
@page "/pos/payment/qr"
@page "/pos/{ShopId:guid}/payment/qr"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Receipt — 80mm thermal printer receipt template with store info, items, totals.
VI: Hóa đơn — Mẫu hóa đơn nhiệt 80mm với thông tin cửa hàng, sản phẩm, tổng tiền.
*@
@page "/pos/payment/receipt"
@page "/pos/{ShopId:guid}/payment/receipt"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Tip Entry — Quick tip buttons, custom tip amount, total with tip display.
VI: Nhập tiền tip — Nút tip nhanh, nhập số tiền tùy chỉnh, hiển thị tổng kèm tip.
*@
@page "/pos/payment/tip"
@page "/pos/{ShopId:guid}/payment/tip"
@layout PosLayout
@inherits PosBase
@using WebClientTpos.Client.Services

View File

@@ -2,7 +2,7 @@
EN: Spa POS Desktop — 2-panel layout: service categories + grid (left), current appointment/bill (right).
VI: POS Spa Desktop — Bố cục 2 panel: danh mục dịch vụ + lưới (trái), lịch hẹn/hóa đơn hiện tại (phải).
*@
@page "/pos/spa"
@page "/pos/{ShopId:guid}/spa"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -126,8 +126,6 @@
</div>
@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;
@@ -155,7 +153,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(SpaShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
_services = apiProducts.Select(p => new SpaService(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Spa POS Mobile — Single column: categories, service grid, floating appointment button, bottom sheet.
VI: POS Spa Mobile — Một cột: danh mục, lưới dịch vụ, nút lịch hẹn nổi, sheet dưới.
*@
@page "/pos/spa/mobile"
@page "/pos/{ShopId:guid}/spa/mobile"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -113,8 +113,6 @@
</div>
@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;
@@ -138,7 +136,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(SpaShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
_services = apiProducts.Select(p => new SpaService(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Spa POS Tablet — 2-column layout: service grid + appointment sidebar (340px), touch-friendly.
VI: POS Spa Tablet — Bố cục 2 cột: lưới dịch vụ + sidebar lịch hẹn (340px), thân thiện cảm ứng.
*@
@page "/pos/spa/tablet"
@page "/pos/{ShopId:guid}/spa/tablet"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -101,8 +101,6 @@
</div>
@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;
@@ -125,7 +123,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(SpaShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
_services = apiProducts.Select(p => new SpaService(
p.Name,

View File

@@ -2,7 +2,7 @@
EN: Spa Appointment Book — Date picker, time slots grid (9:00-20:00), staff selection, service, confirm.
VI: Đặt lịch hẹn Spa — Chọn ngày, lưới khung giờ (9:00-20:00), chọn nhân viên, dịch vụ, xác nhận.
*@
@page "/pos/spa/appointment-book"
@page "/pos/{ShopId:guid}/spa/appointment-book"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -159,8 +159,6 @@
</div>
@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;
@@ -192,7 +190,7 @@
{
try
{
var appointments = await DataService.GetAppointmentsAsync(SpaShopId);
var appointments = await DataService.GetAppointmentsAsync(ShopId);
var bookedTimes = appointments
.Select(a => a.StartTime.ToString("HH:mm"))
@@ -211,7 +209,7 @@
}
_timeSlots = slots;
var products = await DataService.GetProductsAsync(SpaShopId);
var products = await DataService.GetProductsAsync(ShopId);
_selectedServices = products.Take(2).Select(p => new ServiceInfo(
p.Name,
p.Price,

View File

@@ -2,7 +2,7 @@
EN: Spa Customer Lookup — Search by phone/name, results with VIP tier, last visit, create new customer.
VI: Tra cứu khách Spa — Tìm theo SĐT/tên, kết quả với hạng VIP, lần ghé cuối, tạo khách mới.
*@
@page "/pos/spa/customer-lookup"
@page "/pos/{ShopId:guid}/spa/customer-lookup"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Spa Customer Profile — Photo, VIP tier badge, points, progress bar, visit history, favorites, rewards.
VI: Hồ sơ khách Spa — Ảnh, badge hạng VIP, điểm, thanh tiến trình, lịch sử ghé, yêu thích, phần thưởng.
*@
@page "/pos/spa/customer-profile"
@page "/pos/{ShopId:guid}/spa/customer-profile"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Spa Service Combo — Active combos/promotions, bundle discounts, buy 2 get 1, timer, apply combo.
VI: Combo dịch vụ Spa — Combo/khuyến mãi đang áp dụng, giảm giá gộp, mua 2 tặng 1, đếm ngược, áp dụng.
*@
@page "/pos/spa/service-combo"
@page "/pos/{ShopId:guid}/spa/service-combo"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Spa Service Package — Package list with included services, price, savings, expand details, add to appointment.
VI: Gói dịch vụ Spa — Danh sách gói với dịch vụ bao gồm, giá, tiết kiệm, mở rộng chi tiết, thêm vào lịch hẹn.
*@
@page "/pos/spa/service-package"
@page "/pos/{ShopId:guid}/spa/service-package"
@layout PosLayout
@inherits PosBase
@inject WebClientTpos.Client.Services.PosDataService DataService
@@ -119,8 +119,6 @@
</div>
@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;
@@ -149,7 +147,7 @@
{
try
{
var apiProducts = await DataService.GetProductsAsync(SpaShopId);
var apiProducts = await DataService.GetProductsAsync(ShopId);
var productLookup = apiProducts.ToDictionary(p => p.Name, p => p);
_packages = PackageConfigs.Select(cfg =>

View File

@@ -2,7 +2,7 @@
EN: Spa Journey Tracker — Horizontal step tracker: Check-in → Dịch vụ → Thực hiện → Thanh toán → Hoàn tất.
VI: Theo dõi hành trình Spa — Thanh bước ngang: Check-in → Dịch vụ → Thực hiện → Thanh toán → Hoàn tất.
*@
@page "/pos/spa/spa-journey"
@page "/pos/{ShopId:guid}/spa/spa-journey"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Spa Staff Assignment — Staff list with photo, name, specialization, rating, availability, skills tags.
VI: Phân công nhân viên Spa — Danh sách nhân viên với ảnh, tên, chuyên môn, đánh giá, tình trạng, thẻ kỹ năng.
*@
@page "/pos/spa/staff-assign"
@page "/pos/{ShopId:guid}/spa/staff-assign"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Therapist Schedule — Calendar day view with horizontal timeline, staff rows, appointment blocks, current time.
VI: Lịch kỹ thuật viên — Xem theo ngày với timeline ngang, hàng nhân viên, khối lịch hẹn, thời gian hiện tại.
*@
@page "/pos/spa/therapist-schedule"
@page "/pos/{ShopId:guid}/spa/therapist-schedule"
@layout PosLayout
@inherits PosBase

View File

@@ -2,7 +2,7 @@
EN: Spa Treatment Timer — Large circular countdown, service info, customer/therapist, extend time, complete, notes.
VI: Đồng hồ trị liệu Spa — Đếm ngược tròn lớn, thông tin dịch vụ, khách/KTV, gia hạn, hoàn thành, ghi chú.
*@
@page "/pos/spa/treatment-timer"
@page "/pos/{ShopId:guid}/spa/treatment-timer"
@layout PosLayout
@inherits PosBase