@* 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/{ShopId:guid}/spa" @layout PosLayout @inherits PosBase @inject WebClientTpos.Client.Services.PosDataService DataService @* ═══ SERVICE PANEL (LEFT) / PANEL DỊCH VỤ (TRÁI) ═══ *@
@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) {
@svc.Name @FormatPrice(svc.Price) @svc.Duration phút
}
}
@* ═══ APPOINTMENT PANEL (RIGHT) / PANEL LỊCH HẸN (PHẢI) ═══ *@
Lịch hẹn @_appointmentItems.Count dịch vụ
@* EN: Customer info / VI: Thông tin khách *@ @if (_customerName is not null) {
@_customerName[..1]
@_customerName
@_customerPhone • @_customerTier
} else {
}
@foreach (var item in _appointmentItems) {
@item.Name
@FormatPrice(item.Price) @item.Duration phút
}
@code { // EN: Loading state / VI: Trạng thái tải private bool _isLoading = true; private bool _loadError; // EN: Categories / VI: Danh mục private string[] _categories = { "Tất cả" }; private string _selectedCategory = "Tất cả"; // EN: Demo customer / VI: Khách hàng mẫu private string? _customerName = "Nguyễn Thị Mai"; private string _customerPhone = "0901234567"; private string _customerTier = "Gold"; // 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(); private IEnumerable FilteredServices => _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(ShopId); _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)); } private void RemoveItem(AppointmentItem item) => _appointmentItems.Remove(item); private void Checkout() => NavigateTo("spa/spa-journey"); private static string GetCategoryIcon(string category) => category switch { "Massage" => "hand", "Facial" => "sparkles", "Body" => "bath", "Nail" => "paintbrush", "Hair" => "scissors", _ => "heart" }; // EN: Models / VI: Mô hình dữ liệu private record SpaService(string Name, decimal Price, int Duration, string Category); private record AppointmentItem(string Name, decimal Price, int Duration); }