Files
worker/lib/features/cart/presentation/widgets/checkout_submit_button.dart
Phuoc Nguyen 19d9a3dc2d update loaing
2025-12-02 18:09:20 +07:00

189 lines
5.9 KiB
Dart

/// Checkout Submit Button Widget
///
/// Place order or send negotiation request button.
library;
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:worker/core/widgets/loading_indicator.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/core/router/app_router.dart';
import 'package:worker/core/theme/colors.dart';
import 'package:worker/features/account/domain/entities/address.dart';
import 'package:worker/features/orders/presentation/providers/order_repository_provider.dart';
/// Checkout Submit Button
///
/// Button that changes based on negotiation checkbox state.
class CheckoutSubmitButton extends HookConsumerWidget {
const CheckoutSubmitButton({
super.key,
required this.formKey,
required this.ignorePricingRule,
required this.contractRequest,
required this.needsInvoice,
required this.selectedAddress,
required this.paymentMethod,
required this.total,
required this.cartItems,
this.notes,
});
final GlobalKey<FormState> formKey;
final bool ignorePricingRule;
final bool contractRequest;
final bool needsInvoice;
final Address? selectedAddress;
final String paymentMethod;
final double total;
final List<Map<String, dynamic>> cartItems;
final String? notes;
@override
Widget build(BuildContext context, WidgetRef ref) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
child: ElevatedButton(
onPressed: () {
// Validate address is selected
if (selectedAddress == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Vui lòng chọn địa chỉ giao hàng'),
backgroundColor: AppColors.danger,
duration: Duration(seconds: 2),
),
);
return;
}
if (formKey.currentState?.validate() ?? false) {
_handlePlaceOrder(context, ref);
}
},
style: ElevatedButton.styleFrom(
backgroundColor: ignorePricingRule
? AppColors.warning
: colorScheme.primary,
foregroundColor: colorScheme.surface,
padding: const EdgeInsets.symmetric(vertical: 16),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.button),
),
),
child: Text(
ignorePricingRule ? 'Gửi yêu cầu đàm phán' : 'Đặt hàng',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
);
}
/// Handle place order
Future<void> _handlePlaceOrder(BuildContext context, WidgetRef ref) async {
// Show loading indicator
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (context) => Center(
child: CustomLoadingIndicator(color: Theme.of(context).colorScheme.primary, size: 40),
),
);
try {
// Prepare delivery address data
final deliveryAddressData = {
'name': selectedAddress!.name,
'phone': selectedAddress!.phone,
'street': selectedAddress!.addressLine1,
'ward': selectedAddress!.wardName ?? selectedAddress!.wardCode,
'city': selectedAddress!.cityName ?? selectedAddress!.cityCode,
};
// Prepare items data for API
// quantity = boxes/pieces (viên), quantityConverted = m²
// price = quantityConverted * basePrice
final itemsData = cartItems.map((item) {
return {
'item_id': item['sku'] as String,
'quantity': item['quantity'] as double,
'quantityConverted': item['quantityConverted'] as double,
'price': (item['quantityConverted'] as double) * (item['price'] as double),
};
}).toList();
// Call create order API
final result = await ref.read(createOrderProvider(
items: itemsData,
deliveryAddress: deliveryAddressData,
paymentMethod: paymentMethod,
needsInvoice: needsInvoice,
ignorePricingRule: ignorePricingRule,
contractRequest: contractRequest,
notes: notes,
).future);
// Extract order number from response
final orderNumber = result['orderNumber'] as String? ??
result['orderId'] as String? ??
'DH${DateTime.now().millisecondsSinceEpoch.toString().substring(7)}';
if (ignorePricingRule) {
// Navigate to order success page with negotiation flag
if (context.mounted) {
Navigator.of(context).pop();
context.pushReplacementNamed(
RouteNames.orderSuccess,
queryParameters: {
'orderNumber': orderNumber,
'total': total.toString(),
'isNegotiation': 'true',
},
);
}
} else {
// Close loading dialog
if (context.mounted) {
Navigator.of(context).pop();
}
// Navigate to payment QR page (it will fetch QR code data itself)
if (context.mounted) {
context.pushReplacementNamed(
RouteNames.paymentQr,
queryParameters: {
'orderId': orderNumber,
'amount': total.toString(),
},
);
}
}
} catch (e) {
// Close loading dialog
if (context.mounted) {
Navigator.of(context).pop();
}
// Show error message
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Lỗi khi tạo đơn hàng: ${e.toString()}'),
backgroundColor: AppColors.danger,
duration: const Duration(seconds: 3),
),
);
}
}
}
}