193 lines
6.6 KiB
Dart
193 lines
6.6 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:go_router/go_router.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
|
|
import 'package:worker/core/constants/ui_constants.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 controllers
|
|
final nameController = useTextEditingController(text: 'Hoàng Minh Hiệp');
|
|
final phoneController = useTextEditingController(text: '0347302911');
|
|
final addressController = useTextEditingController();
|
|
final notesController = useTextEditingController();
|
|
|
|
// Dropdown selections
|
|
final selectedProvince = useState<String?>('TP.HCM');
|
|
final selectedWard = useState<String?>('Quận 1');
|
|
final selectedPickupDate = useState<DateTime?>(null);
|
|
|
|
// Invoice section
|
|
final needsInvoice = useState<bool>(false);
|
|
final companyNameController = useTextEditingController();
|
|
final taxIdController = useTextEditingController();
|
|
final companyAddressController = useTextEditingController();
|
|
final companyEmailController = useTextEditingController();
|
|
|
|
// Payment method
|
|
final paymentMethod = useState<String>('bank_transfer');
|
|
|
|
// 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 Icon(Icons.arrow_back, color: Colors.black),
|
|
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(
|
|
nameController: nameController,
|
|
phoneController: phoneController,
|
|
addressController: addressController,
|
|
notesController: notesController,
|
|
selectedProvince: selectedProvince,
|
|
selectedWard: selectedWard,
|
|
selectedPickupDate: selectedPickupDate,
|
|
),
|
|
|
|
const SizedBox(height: AppSpacing.md),
|
|
|
|
// Invoice Section
|
|
InvoiceSection(
|
|
needsInvoice: needsInvoice,
|
|
companyNameController: companyNameController,
|
|
taxIdController: taxIdController,
|
|
companyAddressController: companyAddressController,
|
|
companyEmailController: companyEmailController,
|
|
),
|
|
|
|
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,
|
|
name: nameController.text,
|
|
phone: phoneController.text,
|
|
address: addressController.text,
|
|
province: selectedProvince.value,
|
|
ward: selectedWard.value,
|
|
paymentMethod: paymentMethod.value,
|
|
companyName: companyNameController.text,
|
|
taxId: taxIdController.text,
|
|
total: total,
|
|
),
|
|
|
|
const SizedBox(height: AppSpacing.lg),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|