add account, checkout page
This commit is contained in:
192
lib/features/cart/presentation/pages/checkout_page.dart
Normal file
192
lib/features/cart/presentation/pages/checkout_page.dart
Normal file
@@ -0,0 +1,192 @@
|
||||
/// 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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user