diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/BankTransfer.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/BankTransfer.razor new file mode 100644 index 00000000..99820116 --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/BankTransfer.razor @@ -0,0 +1,75 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ ORDER TOTAL ═══ *@ +
+
Tổng thanh toán
+
@FormatPrice(_orderTotal)
+
+ + @* ═══ BANK ACCOUNT INFO ═══ *@ +
+
Thông tin chuyển khoản
+ +
+ Ngân hàng + @_bankName +
+
+ Số tài khoản + @_accountNumber +
+
+ Chủ tài khoản + @_accountHolder +
+ + @* EN: Transfer reference / VI: Mã tham chiếu *@ +
+
Nội dung chuyển khoản
+
@_referenceCode
+
+
+ + @* ═══ STATUS ═══ *@ +
+
+ Chờ xác nhận chuyển khoản... +
+ + @* ═══ ACTIONS ═══ *@ +
+ + +
+
+ + + +@code { + // EN: Demo data / VI: Dữ liệu mẫu + private decimal _orderTotal = 285_000; + private string _bankName = "Vietcombank"; + private string _accountNumber = "1017 6688 9900"; + private string _accountHolder = "CONG TY TNHH GOODGO"; + private string _referenceCode = "GG240215A1"; + + private void Verify() => NavigateTo("payment/success"); + private void Cancel() => NavigateTo("payment/method-select"); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/CardPayment.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/CardPayment.razor new file mode 100644 index 00000000..2926ae3c --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/CardPayment.razor @@ -0,0 +1,76 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ ORDER TOTAL ═══ *@ +
+
Tổng thanh toán
+
@FormatPrice(_orderTotal)
+
+ + @* ═══ CARD READER STATUS ═══ *@ +
+ @if (_isProcessing) + { + @* EN: Processing animation / VI: Hiệu ứng đang xử lý *@ +
+
Đang xử lý...
+
Vui lòng không rút thẻ
+ } + else + { + @* EN: Waiting for card / VI: Chờ thẻ *@ +
+ +
+
Chạm, quẹt hoặc cắm thẻ
+
Tap, swipe or insert card
+ } +
+ + @* ═══ ACTIONS ═══ *@ +
+ @if (!_isProcessing) + { + + } + +
+
+ +@* EN: CSS animations / VI: Hiệu ứng CSS *@ + + +@code { + // EN: Demo order total / VI: Tổng đơn hàng mẫu + private decimal _orderTotal = 285_000; + private bool _isProcessing = false; + + private async Task SimulateProcess() + { + _isProcessing = true; + StateHasChanged(); + await Task.Delay(3000); + NavigateTo("payment/success"); + } + + private void Cancel() => NavigateTo("payment/method-select"); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/CashPayment.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/CashPayment.razor new file mode 100644 index 00000000..240d775d --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/CashPayment.razor @@ -0,0 +1,109 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ MAIN PANEL ═══ *@ +
+ @* ═══ ORDER TOTAL ═══ *@ +
+
Tổng thanh toán
+
@FormatPrice(_orderTotal)
+
+ + @* ═══ QUICK AMOUNT BUTTONS ═══ *@ +
+
Số tiền nhanh
+
+ @foreach (var amount in _quickAmounts) + { + + } +
+
+ + @* ═══ CUSTOM AMOUNT INPUT ═══ *@ +
+
Nhập số tiền khác
+
+ + +
+
+ + @* ═══ CHANGE DISPLAY ═══ *@ +
+
+ Khách đưa + @FormatPrice(_receivedAmount) +
+
+ Tiền thối + + @FormatPrice(_changeAmount) + +
+
+
+ + @* ═══ CONFIRM PANEL ═══ *@ +
+ + +
+
+ +@code { + // EN: Demo order total / VI: Tổng đơn hàng mẫu + private decimal _orderTotal = 285_000; + private decimal _receivedAmount = 0; + private decimal _changeAmount => _receivedAmount - _orderTotal; + private string _customInput = ""; + + // EN: Quick amount options / VI: Tùy chọn số tiền nhanh + private readonly List _quickAmounts = new() + { + new("300,000₫", 300_000), + new("350,000₫", 350_000), + new("400,000₫", 400_000), + new("500,000₫", 500_000), + new("1,000,000₫", 1_000_000), + new("Đúng tiền", 285_000), + }; + + private void SetAmount(decimal amount) => _receivedAmount = amount; + + private void ApplyCustom() + { + if (decimal.TryParse(_customInput, out var val)) + _receivedAmount = val; + } + + private void Confirm() => NavigateTo("payment/success"); + private void GoBack() => NavigateTo("payment/method-select"); + + private record QuickAmount(string Label, decimal Value); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/GiftCardPayment.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/GiftCardPayment.razor new file mode 100644 index 00000000..311d2412 --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/GiftCardPayment.razor @@ -0,0 +1,109 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ ORDER TOTAL ═══ *@ +
+
Tổng thanh toán
+
@FormatPrice(_orderTotal)
+
+ + @* ═══ GIFT CARD INPUT ═══ *@ +
+
+ + Thẻ quà tặng +
+ +
+ + +
+ + @if (_cardLookedUp) + { + @* ═══ CARD BALANCE ═══ *@ +
+
+ Số dư thẻ + @FormatPrice(_cardBalance) +
+
+ Số tiền áp dụng + @FormatPrice(_appliedAmount) +
+ + @if (_remainingAmount > 0) + { + @* EN: Remaining balance warning / VI: Cảnh báo số dư còn thiếu *@ +
+
+ + Còn thiếu: @FormatPrice(_remainingAmount) +
+
+ Vui lòng thanh toán phần còn lại bằng phương thức khác +
+
+ } +
+ } +
+ + @* ═══ ACTIONS ═══ *@ +
+ @if (_cardLookedUp) + { + @if (_remainingAmount > 0) + { + + } + else + { + + } + } + +
+
+ +@code { + // EN: Demo data / VI: Dữ liệu mẫu + private decimal _orderTotal = 285_000; + private string _cardCode = ""; + private bool _cardLookedUp = false; + private decimal _cardBalance = 200_000; + private decimal _appliedAmount => Math.Min(_cardBalance, _orderTotal); + private decimal _remainingAmount => Math.Max(0, _orderTotal - _cardBalance); + + private void LookupCard() + { + // EN: Simulate card lookup / VI: Mô phỏng tra cứu thẻ + _cardLookedUp = true; + } + + private void Confirm() => NavigateTo("payment/success"); + private void GoToPartial() => NavigateTo("payment/partial"); + private void Cancel() => NavigateTo("payment/method-select"); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/MethodSelect.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/MethodSelect.razor new file mode 100644 index 00000000..3d3c189f --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/MethodSelect.razor @@ -0,0 +1,57 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ ORDER TOTAL ═══ *@ +
+
Tổng đơn hàng / Order Total
+
@FormatPrice(_orderTotal)
+
+ + @* ═══ PAYMENT METHODS ═══ *@ +
+ @foreach (var method in _methods) + { + + } +
+ + @* ═══ BACK BUTTON ═══ *@ + +
+ +@code { + // EN: Demo order total / VI: Tổng đơn hàng mẫu + private decimal _orderTotal = 285_000; + + // EN: Payment method definitions / VI: Định nghĩa phương thức thanh toán + private readonly List _methods = new() + { + new("💵", "Tiền mặt", "Thanh toán bằng tiền mặt", "payment/cash"), + new("💳", "Thẻ", "Chạm, quẹt hoặc cắm thẻ", "payment/card"), + new("📱", "Mã QR", "VietQR, MoMo, ZaloPay", "payment/qr"), + new("🎁", "Thẻ quà tặng", "Sử dụng thẻ quà tặng", "payment/gift-card"), + }; + + private void SelectMethod(string route) => NavigateTo(route); + private void GoBack() => NavigateTo("cafe"); + + private record PaymentMethod(string Icon, string Label, string Description, string Route); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PartialPayment.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PartialPayment.razor new file mode 100644 index 00000000..280d6b22 --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PartialPayment.razor @@ -0,0 +1,139 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ MAIN PANEL ═══ *@ +
+ @* ═══ ORDER TOTAL ═══ *@ +
+
Tổng đơn hàng
+
@FormatPrice(_orderTotal)
+
+ + @* ═══ PAYMENT SPLITS ═══ *@ +
+
Phương thức thanh toán đã thêm
+ @foreach (var split in _splits) + { +
+ @split.Icon +
+
@split.Method
+
@split.Description
+
+ @FormatPrice(split.Amount) + +
+ } +
+ + @* ═══ ADD METHOD ═══ *@ + @if (_remainingBalance > 0) + { +
+
Thêm phương thức
+
+ @foreach (var option in _addOptions) + { + + } +
+
+ } +
+ + @* ═══ SUMMARY PANEL ═══ *@ +
+
Tóm tắt thanh toán
+ +
+
+ Tổng đơn hàng + @FormatPrice(_orderTotal) +
+
+ Đã thanh toán + @FormatPrice(_paidAmount) +
+
+ Còn lại + + @FormatPrice(_remainingBalance) + +
+ + @* EN: Progress bar / VI: Thanh tiến trình *@ +
+
+
+
+ +
+ + +
+
+
+ +@code { + // EN: Demo data / VI: Dữ liệu mẫu + private decimal _orderTotal = 285_000; + + private readonly List _splits = new() + { + new("💵", "Tiền mặt", "Cash", 150_000), + new("💳", "Thẻ", "Card ending 4242", 135_000), + }; + + private readonly List _addOptions = new() + { + new("💵", "Tiền mặt"), + new("💳", "Thẻ"), + new("📱", "Mã QR"), + new("🎁", "Thẻ quà tặng"), + }; + + private decimal _paidAmount => _splits.Sum(s => s.Amount); + private decimal _remainingBalance => Math.Max(0, _orderTotal - _paidAmount); + private int _progressPercent => (int)Math.Min(100, _paidAmount / _orderTotal * 100); + + private void AddSplit(AddOption option) + { + _splits.Add(new(option.Icon, option.Label, "Mới thêm", _remainingBalance)); + } + + private void RemoveSplit(PaymentSplit split) => _splits.Remove(split); + private void Complete() => NavigateTo("payment/success"); + private void GoBack() => NavigateTo("payment/method-select"); + + private record AddOption(string Icon, string Label); + private class PaymentSplit(string icon, string method, string description, decimal amount) + { + public string Icon { get; set; } = icon; + public string Method { get; set; } = method; + public string Description { get; set; } = description; + public decimal Amount { get; set; } = amount; + } +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PaymentPending.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PaymentPending.razor new file mode 100644 index 00000000..818f4017 --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PaymentPending.razor @@ -0,0 +1,64 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ PROCESSING ANIMATION ═══ *@ +
+
+
+
+
+ +
+
+ + @* ═══ STATUS MESSAGE ═══ *@ +
+
Đang xử lý thanh toán...
+
Processing payment...
+
+ + @* ═══ PAYMENT INFO ═══ *@ +
+
+ Tổng thanh toán + @FormatPrice(_orderTotal) +
+
+ Phương thức + @_paymentMethod +
+
+ Mã giao dịch + @_transactionId +
+
+ + @* ═══ CANCEL BUTTON ═══ *@ + +
+ + + +@code { + // EN: Demo data / VI: Dữ liệu mẫu + private decimal _orderTotal = 285_000; + private string _paymentMethod = "Thẻ (Visa •••• 4242)"; + private string _transactionId = "TXN-20240215-001"; + + private void Cancel() => NavigateTo("payment/method-select"); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PaymentSuccess.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PaymentSuccess.razor new file mode 100644 index 00000000..d77a8f87 --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/PaymentSuccess.razor @@ -0,0 +1,84 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ SUCCESS ANIMATION ═══ *@ +
+
+ +
+
+ + @* ═══ SUCCESS MESSAGE ═══ *@ +
+
Thanh toán thành công!
+
Payment successful
+
+ + @* ═══ TRANSACTION DETAILS ═══ *@ +
+
+ Tổng thanh toán + @FormatPrice(_orderTotal) +
+
+ Phương thức + @_paymentMethod +
+ @if (_changeAmount > 0) + { +
+ Tiền thối + @FormatPrice(_changeAmount) +
+ } +
+ Mã giao dịch + @_transactionId +
+
+ Thời gian + @DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss") +
+
+ + @* ═══ ACTION BUTTONS ═══ *@ +
+ + +
+
+ + + +@code { + // EN: Demo data / VI: Dữ liệu mẫu + private decimal _orderTotal = 285_000; + private string _paymentMethod = "Tiền mặt"; + private decimal _changeAmount = 15_000; + private string _transactionId = "TXN-20240215-001"; + + private void PrintReceipt() => NavigateTo("payment/receipt"); + private void NewOrder() => NavigateTo("cafe"); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/QrPayment.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/QrPayment.razor new file mode 100644 index 00000000..cd8d04a2 --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/QrPayment.razor @@ -0,0 +1,79 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ ORDER TOTAL ═══ *@ +
+
Tổng thanh toán
+
@FormatPrice(_orderTotal)
+
+ + @* ═══ QR PROVIDER TABS ═══ *@ +
+ @foreach (var provider in _providers) + { + + } +
+ + @* ═══ QR CODE DISPLAY ═══ *@ +
+ + @_selectedProvider +
+ + @* ═══ TIMER ═══ *@ +
+ + @_timerDisplay +
+ + @* ═══ STATUS ═══ *@ +
+
+ Chờ xác nhận thanh toán... +
+ + @* ═══ ACTIONS ═══ *@ +
+ + +
+
+ + + +@code { + // EN: Demo order total / VI: Tổng đơn hàng mẫu + private decimal _orderTotal = 285_000; + private string _selectedProvider = "VietQR"; + private int _timerSeconds = 300; + private string _timerDisplay => $"{_timerSeconds / 60}:{(_timerSeconds % 60):D2}"; + + // EN: QR providers / VI: Nhà cung cấp QR + private readonly string[] _providers = { "VietQR", "MoMo", "ZaloPay" }; + + private void Refresh() => _timerSeconds = 300; + private void Cancel() => NavigateTo("payment/method-select"); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/Receipt.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/Receipt.razor new file mode 100644 index 00000000..408bb2ce --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/Receipt.razor @@ -0,0 +1,153 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ RECEIPT PAPER ═══ *@ +
+ @* ═══ STORE HEADER ═══ *@ +
+
GOODGO COFFEE
+
123 Nguyễn Huệ, Q.1, TP.HCM
+
ĐT: 028-1234-5678
+
+ + @* EN: Dashed separator / VI: Đường kẻ đứt *@ +
+ + @* ═══ ORDER INFO ═══ *@ +
+ Đơn #@_orderNumber + @_orderDate +
+
NV: @_staffName
+ +
+ + @* ═══ ITEM LIST ═══ *@ + @foreach (var item in _items) + { +
+ @item.Qty x @item.Name + @FormatReceiptPrice(item.Price * item.Qty) +
+ } + +
+ + @* ═══ TOTALS ═══ *@ +
+
+ Tạm tính + @FormatReceiptPrice(_subtotal) +
+
+ Phí dịch vụ (5%) + @FormatReceiptPrice(_serviceCharge) +
+
+ VAT (8%) + @FormatReceiptPrice(_vat) +
+
+ +
+ +
+ TỔNG CỘNG + @FormatReceiptPrice(_total) +
+ +
+ + @* ═══ PAYMENT INFO ═══ *@ +
+
+ Thanh toán + @_paymentMethod +
+
+ Khách đưa + @FormatReceiptPrice(_amountPaid) +
+
+ Tiền thối + @FormatReceiptPrice(_changeAmount) +
+
+ +
+ + @* ═══ TRANSACTION ID ═══ *@ +
+
Mã GD: @_transactionId
+
@_orderDate @_orderTime
+
+ +
+ + @* ═══ FOOTER ═══ *@ +
+ Cảm ơn quý khách! +
+
+ Thank you & see you again! +
+
+
+ +@* ═══ ACTION BUTTONS (fixed bottom) ═══ *@ +
+ + +
+ +@code { + // EN: Demo receipt data / VI: Dữ liệu hóa đơn mẫu + private string _orderNumber = "1042"; + private string _orderDate = "15/02/2024"; + private string _orderTime = "14:35:22"; + private string _staffName = "Nguyễn Thị Mai"; + + private readonly List _items = new() + { + new("Cà phê sữa đá", 35_000, 2), + new("Cappuccino", 55_000, 1), + new("Croissant bơ", 35_000, 1), + new("Trà đào cam sả", 45_000, 1), + new("Bánh mì thịt", 30_000, 1), + }; + + private decimal _subtotal => _items.Sum(i => i.Price * i.Qty); + private decimal _serviceCharge => Math.Round(_subtotal * 0.05m); + private decimal _vat => Math.Round(_subtotal * 0.08m); + private decimal _total => _subtotal + _serviceCharge + _vat; + private string _paymentMethod = "Tiền mặt"; + private decimal _amountPaid = 300_000; + private decimal _changeAmount => _amountPaid - _total; + private string _transactionId = "TXN-20240215-001"; + + private static string FormatReceiptPrice(decimal price) => price.ToString("N0") + "₫"; + + private void Print() + { + // EN: Trigger browser print / VI: Kích hoạt in từ trình duyệt + } + + private void Close() => NavigateTo("payment/success"); + + private record ReceiptItem(string Name, decimal Price, int Qty); +} diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/TipEntry.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/TipEntry.razor new file mode 100644 index 00000000..d69439b4 --- /dev/null +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Pos/Shared/Payment/TipEntry.razor @@ -0,0 +1,122 @@ +@* + 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" +@layout PosLayout +@inherits PosBase + +
+ @* ═══ SUBTOTAL ═══ *@ +
+
Tạm tính / Subtotal
+
@FormatPrice(_subtotal)
+
+ + @* ═══ QUICK TIP BUTTONS ═══ *@ +
+
Chọn mức tip
+
+ @foreach (var tip in _tipOptions) + { + + } +
+
+ + @* ═══ CUSTOM TIP INPUT ═══ *@ + @if (_showCustomInput) + { +
+ + +
+ } + + @* ═══ TOTAL WITH TIP ═══ *@ +
+
+ Tạm tính + @FormatPrice(_subtotal) +
+
+ Tiền tip + +@FormatPrice(_tipAmount) +
+
+ Tổng cộng + @FormatPrice(_subtotal + _tipAmount) +
+
+ + @* ═══ ACTIONS ═══ *@ +
+ + +
+
+ +@code { + // EN: Demo subtotal / VI: Tạm tính mẫu + private decimal _subtotal = 285_000; + private decimal _tipAmount = 0; + private string _selectedTip = ""; + private bool _showCustomInput = false; + private decimal _customTipAmount = 0; + + // EN: Tip options / VI: Tùy chọn tip + private readonly List _tipOptions = new() + { + new("5%", 5), + new("10%", 10), + new("15%", 15), + new("20%", 20), + new("Khác", 0), + }; + + private void SelectTip(TipOption tip) + { + _selectedTip = tip.Label; + if (tip.Percent > 0) + { + _tipAmount = Math.Round(_subtotal * tip.Percent / 100); + _showCustomInput = false; + } + else + { + _showCustomInput = true; + } + } + + private void ApplyCustomTip() + { + _tipAmount = _customTipAmount; + } + + private void Skip() => NavigateTo("payment/method-select"); + private void Confirm() => NavigateTo("payment/method-select"); + + private record TipOption(string Label, decimal Percent); +}