create order

This commit is contained in:
Phuoc Nguyen
2025-11-21 16:50:43 +07:00
parent f2f95849d4
commit 4913a4e04b
31 changed files with 1696 additions and 187 deletions

View File

@@ -26,6 +26,8 @@ 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';
import 'package:worker/features/orders/presentation/providers/order_status_provider.dart';
import 'package:worker/features/orders/presentation/providers/payment_terms_provider.dart';
/// Checkout Page
///
@@ -51,12 +53,15 @@ class CheckoutPage extends HookConsumerWidget {
// Invoice section
final needsInvoice = useState<bool>(false);
// Payment method
final paymentMethod = useState<String>('full_payment');
// Payment method (will be set to first payment term name from API)
final paymentMethod = useState<String>('');
// Price negotiation
final needsNegotiation = useState<bool>(false);
// Watch API provider for payment terms
final paymentTermsListAsync = ref.watch(paymentTermsListProvider);
// Get CartItemData from navigation
final cartItemsData = checkoutData?['cartItems'] as List<dynamic>? ?? [];
@@ -85,7 +90,7 @@ class CheckoutPage extends HookConsumerWidget {
);
// TODO: Fetch member discount from user profile API
const memberDiscountPercent = 15.0; // Diamond tier (temporary)
const memberDiscountPercent = 0.0; // Temporarily disabled (was 15.0 for Diamond tier)
final memberDiscount = subtotal * (memberDiscountPercent / 100);
// TODO: Fetch shipping fee from API based on address
@@ -140,7 +145,78 @@ class CheckoutPage extends HookConsumerWidget {
// Payment Method Section (hidden if negotiation is checked)
if (!needsNegotiation.value)
PaymentMethodSection(paymentMethod: paymentMethod),
paymentTermsListAsync.when(
data: (paymentTerms) {
// Set default payment method to first term if not set
if (paymentMethod.value.isEmpty && paymentTerms.isNotEmpty) {
WidgetsBinding.instance.addPostFrameCallback((_) {
paymentMethod.value = paymentTerms.first.name;
});
}
return PaymentMethodSection(
paymentMethod: paymentMethod,
paymentTerms: paymentTerms,
);
},
loading: () => Container(
margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(AppRadius.card),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: const Center(
child: CircularProgressIndicator(),
),
),
error: (error, stack) => Container(
margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(AppRadius.card),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
const Icon(
FontAwesomeIcons.triangleExclamation,
color: AppColors.danger,
size: 32,
),
const SizedBox(height: 12),
Text(
'Không thể tải phương thức thanh toán',
style: const TextStyle(
fontSize: 14,
color: AppColors.grey500,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
TextButton(
onPressed: () {
ref.invalidate(paymentTermsListProvider);
},
child: const Text('Thử lại'),
),
],
),
),
),
if (!needsNegotiation.value)
const SizedBox(height: AppSpacing.md),
@@ -164,6 +240,7 @@ class CheckoutPage extends HookConsumerWidget {
// Price Negotiation Section
PriceNegotiationSection(needsNegotiation: needsNegotiation),
const SizedBox(height: AppSpacing.md),
// Terms and Conditions
@@ -200,6 +277,8 @@ class CheckoutPage extends HookConsumerWidget {
selectedAddress: selectedAddress.value,
paymentMethod: paymentMethod.value,
total: total,
cartItems: checkoutItems,
notes: notesController.text.trim().isEmpty ? null : notesController.text.trim(),
),
const SizedBox(height: AppSpacing.lg),