188 lines
5.8 KiB
Dart
188 lines
5.8 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/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) => const Center(
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
);
|
|
|
|
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),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|