Files
worker/lib/features/cart/presentation/pages/checkout_page.dart
Phuoc Nguyen fc4711a18e fix
2025-11-18 17:59:27 +07:00

170 lines
5.5 KiB
Dart

/// Checkout Page
///
/// Complete checkout flow with delivery info, invoice options, payment methods.
/// Features:
/// - Delivery information form with province/ward dropdowns
/// - Invoice toggle section (checkbox reveals invoice fields)
/// - Payment method selection (bank transfer vs COD)
/// - Order summary with items list
/// - Price negotiation option (hides payment, changes button)
/// - Form validation and submission
library;
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/features/account/domain/entities/address.dart';
import 'package:worker/features/cart/presentation/widgets/checkout_submit_button.dart';
import 'package:worker/features/cart/presentation/widgets/delivery_information_section.dart';
import 'package:worker/features/cart/presentation/widgets/invoice_section.dart';
import 'package:worker/features/cart/presentation/widgets/order_summary_section.dart';
import 'package:worker/features/cart/presentation/widgets/payment_method_section.dart';
import 'package:worker/features/cart/presentation/widgets/price_negotiation_section.dart';
/// Checkout Page
///
/// Full checkout flow for placing orders.
class CheckoutPage extends HookConsumerWidget {
const CheckoutPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// Form key for validation
final formKey = useMemoized(() => GlobalKey<FormState>());
// Delivery information
final notesController = useTextEditingController();
final selectedPickupDate = useState<DateTime?>(null);
final selectedAddress = useState<Address?>(null);
// Invoice section
final needsInvoice = useState<bool>(false);
// Payment method
final paymentMethod = useState<String>('full_payment');
// Price negotiation
final needsNegotiation = useState<bool>(false);
// Mock cart items
final cartItems = useState<List<Map<String, dynamic>>>([
{
'id': '1',
'name': 'Gạch Granite 60x60 Marble White',
'sku': 'GT-6060-MW',
'quantity': 20,
'price': 250000,
'image':
'https://images.unsplash.com/photo-1615971677499-5467cbab01c0?w=200',
},
{
'id': '2',
'name': 'Gạch Ceramic 30x60 Wood Effect',
'sku': 'CR-3060-WE',
'quantity': 15,
'price': 180000,
'image':
'https://images.unsplash.com/photo-1604709177225-055f99402ea3?w=200',
},
]);
// Calculate totals
final subtotal = cartItems.value.fold<double>(
0,
(sum, item) => sum + (item['price'] as int) * (item['quantity'] as int),
);
final discount = subtotal * 0.05; // 5% discount
const shipping = 50000.0;
final total = subtotal - discount + shipping;
return Scaffold(
backgroundColor: const Color(0xFFF4F6F8),
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: IconButton(
icon: const FaIcon(
FontAwesomeIcons.arrowLeft,
color: Colors.black,
size: 20,
),
onPressed: () => context.pop(),
),
title: const Text(
'Thanh toán',
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
centerTitle: false,
actions: const [SizedBox(width: AppSpacing.sm)],
),
body: Form(
key: formKey,
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: AppSpacing.md),
// Delivery Information Section
DeliveryInformationSection(
notesController: notesController,
selectedPickupDate: selectedPickupDate,
selectedAddress: selectedAddress,
),
const SizedBox(height: AppSpacing.md),
// Invoice Section
InvoiceSection(needsInvoice: needsInvoice),
const SizedBox(height: AppSpacing.md),
// Payment Method Section (hidden if negotiation is checked)
if (!needsNegotiation.value)
PaymentMethodSection(paymentMethod: paymentMethod),
if (!needsNegotiation.value)
const SizedBox(height: AppSpacing.md),
// Order Summary Section
OrderSummarySection(
cartItems: cartItems.value,
subtotal: subtotal,
discount: discount,
shipping: shipping,
total: total,
),
const SizedBox(height: AppSpacing.md),
// Price Negotiation Section
PriceNegotiationSection(needsNegotiation: needsNegotiation),
const SizedBox(height: AppSpacing.md),
// Place Order Button
CheckoutSubmitButton(
formKey: formKey,
needsNegotiation: needsNegotiation.value,
needsInvoice: needsInvoice.value,
selectedAddress: selectedAddress.value,
paymentMethod: paymentMethod.value,
total: total,
),
const SizedBox(height: AppSpacing.lg),
],
),
),
),
);
}
}