order success

This commit is contained in:
Phuoc Nguyen
2025-11-24 17:28:17 +07:00
parent 1851d60038
commit c3b5653420
9 changed files with 55 additions and 34 deletions

View File

@@ -56,10 +56,11 @@ class CheckoutPage extends HookConsumerWidget {
// Payment method (will be set to first payment term name from API) // Payment method (will be set to first payment term name from API)
final paymentMethod = useState<String>(''); final paymentMethod = useState<String>('');
// Price negotiation // Price negotiation (ignore_pricing_rule in API)
final needsNegotiation = useState<bool>(false); final ignorePricingRule = useState<bool>(false);
final needsContract = useState(false); // Contract request (contract_request in API)
final contractRequest = useState<bool>(false);
// Watch API provider for payment terms // Watch API provider for payment terms
final paymentTermsListAsync = ref.watch(paymentTermsListProvider); final paymentTermsListAsync = ref.watch(paymentTermsListProvider);
@@ -145,8 +146,8 @@ class CheckoutPage extends HookConsumerWidget {
const SizedBox(height: AppSpacing.md), const SizedBox(height: AppSpacing.md),
// Payment Method Section (hidden if negotiation is checked) // Payment Method Section (hidden if price negotiation is checked)
if (!needsNegotiation.value) if (!ignorePricingRule.value)
paymentTermsListAsync.when( paymentTermsListAsync.when(
data: (paymentTerms) { data: (paymentTerms) {
// Set default payment method to first term if not set // Set default payment method to first term if not set
@@ -220,7 +221,7 @@ class CheckoutPage extends HookConsumerWidget {
), ),
), ),
if (!needsNegotiation.value) if (!ignorePricingRule.value)
const SizedBox(height: AppSpacing.md), const SizedBox(height: AppSpacing.md),
// Discount Code Section // Discount Code Section
@@ -240,7 +241,7 @@ class CheckoutPage extends HookConsumerWidget {
const SizedBox(height: AppSpacing.md), const SizedBox(height: AppSpacing.md),
// Price Negotiation Section // Price Negotiation Section
PriceNegotiationSection(needsNegotiation: needsNegotiation), PriceNegotiationSection(ignorePricingRule: ignorePricingRule),
const SizedBox(height: AppSpacing.md), const SizedBox(height: AppSpacing.md),
@@ -256,9 +257,9 @@ class CheckoutPage extends HookConsumerWidget {
child: Row( child: Row(
children: [ children: [
Checkbox( Checkbox(
value: needsContract.value, value: contractRequest.value,
onChanged: (value) { onChanged: (value) {
needsContract.value = value ?? false; contractRequest.value = value ?? false;
}, },
activeColor: AppColors.warning, activeColor: AppColors.warning,
), ),
@@ -308,7 +309,8 @@ class CheckoutPage extends HookConsumerWidget {
// Place Order Button // Place Order Button
CheckoutSubmitButton( CheckoutSubmitButton(
formKey: formKey, formKey: formKey,
needsNegotiation: needsNegotiation.value, ignorePricingRule: ignorePricingRule.value,
contractRequest: contractRequest.value,
needsInvoice: needsInvoice.value, needsInvoice: needsInvoice.value,
selectedAddress: selectedAddress.value, selectedAddress: selectedAddress.value,
paymentMethod: paymentMethod.value, paymentMethod: paymentMethod.value,

View File

@@ -20,7 +20,8 @@ class CheckoutSubmitButton extends HookConsumerWidget {
const CheckoutSubmitButton({ const CheckoutSubmitButton({
super.key, super.key,
required this.formKey, required this.formKey,
required this.needsNegotiation, required this.ignorePricingRule,
required this.contractRequest,
required this.needsInvoice, required this.needsInvoice,
required this.selectedAddress, required this.selectedAddress,
required this.paymentMethod, required this.paymentMethod,
@@ -30,7 +31,8 @@ class CheckoutSubmitButton extends HookConsumerWidget {
}); });
final GlobalKey<FormState> formKey; final GlobalKey<FormState> formKey;
final bool needsNegotiation; final bool ignorePricingRule;
final bool contractRequest;
final bool needsInvoice; final bool needsInvoice;
final Address? selectedAddress; final Address? selectedAddress;
final String paymentMethod; final String paymentMethod;
@@ -62,7 +64,7 @@ class CheckoutSubmitButton extends HookConsumerWidget {
} }
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: needsNegotiation backgroundColor: ignorePricingRule
? AppColors.warning ? AppColors.warning
: AppColors.primaryBlue, : AppColors.primaryBlue,
foregroundColor: Colors.white, foregroundColor: Colors.white,
@@ -73,7 +75,7 @@ class CheckoutSubmitButton extends HookConsumerWidget {
), ),
), ),
child: Text( child: Text(
needsNegotiation ? 'Gửi yêu cầu đàm phán' : 'Đặt hàng', ignorePricingRule ? 'Gửi yêu cầu đàm phán' : 'Đặt hàng',
style: const TextStyle( style: const TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -122,7 +124,8 @@ class CheckoutSubmitButton extends HookConsumerWidget {
deliveryAddress: deliveryAddressData, deliveryAddress: deliveryAddressData,
paymentMethod: paymentMethod, paymentMethod: paymentMethod,
needsInvoice: needsInvoice, needsInvoice: needsInvoice,
needsNegotiation: needsNegotiation, ignorePricingRule: ignorePricingRule,
contractRequest: contractRequest,
notes: notes, notes: notes,
).future); ).future);
@@ -131,7 +134,7 @@ class CheckoutSubmitButton extends HookConsumerWidget {
result['orderId'] as String? ?? result['orderId'] as String? ??
'DH${DateTime.now().millisecondsSinceEpoch.toString().substring(7)}'; 'DH${DateTime.now().millisecondsSinceEpoch.toString().substring(7)}';
if (needsNegotiation) { if (ignorePricingRule) {
// Navigate to order success page with negotiation flag // Navigate to order success page with negotiation flag
if (context.mounted) { if (context.mounted) {
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@@ -13,8 +13,8 @@ import 'package:worker/core/theme/colors.dart';
/// Allows user to request price negotiation instead of direct order. /// Allows user to request price negotiation instead of direct order.
class PriceNegotiationSection extends HookWidget { class PriceNegotiationSection extends HookWidget {
const PriceNegotiationSection({super.key, required this.needsNegotiation}); const PriceNegotiationSection({super.key, required this.ignorePricingRule});
final ValueNotifier<bool> needsNegotiation; final ValueNotifier<bool> ignorePricingRule;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -29,9 +29,9 @@ class PriceNegotiationSection extends HookWidget {
child: Row( child: Row(
children: [ children: [
Checkbox( Checkbox(
value: needsNegotiation.value, value: ignorePricingRule.value,
onChanged: (value) { onChanged: (value) {
needsNegotiation.value = value ?? false; ignorePricingRule.value = value ?? false;
}, },
activeColor: AppColors.warning, activeColor: AppColors.warning,
), ),

View File

@@ -92,6 +92,8 @@ class OrderRemoteDataSource {
/// "customer_address": "...", /// "customer_address": "...",
/// "description": "...", /// "description": "...",
/// "payment_terms": "...", /// "payment_terms": "...",
/// "ignore_pricing_rule": true,
/// "contract_request": true,
/// "items": [{"item_id": "...", "qty_entered": 0, "primary_qty": 0, "price_entered": 0}] /// "items": [{"item_id": "...", "qty_entered": 0, "primary_qty": 0, "price_entered": 0}]
/// } /// }
/// Returns: { "message": { "name": "SAL-ORD-2025-00001", ... } } /// Returns: { "message": { "name": "SAL-ORD-2025-00001", ... } }
@@ -100,7 +102,8 @@ class OrderRemoteDataSource {
required Map<String, dynamic> deliveryAddress, required Map<String, dynamic> deliveryAddress,
required String paymentMethod, required String paymentMethod,
bool needsInvoice = false, bool needsInvoice = false,
bool needsNegotiation = false, bool ignorePricingRule = false,
bool contractRequest = false,
String? notes, String? notes,
}) async { }) async {
try { try {
@@ -126,6 +129,8 @@ class OrderRemoteDataSource {
'customer_address': deliveryAddress['name'] ?? '', 'customer_address': deliveryAddress['name'] ?? '',
'description': notes ?? 'Order from mobile app', 'description': notes ?? 'Order from mobile app',
'payment_terms': paymentMethod, 'payment_terms': paymentMethod,
'ignore_pricing_rule': ignorePricingRule,
'contract_request': contractRequest,
'items': formattedItems, 'items': formattedItems,
}; };

View File

@@ -98,7 +98,8 @@ class OrderRepositoryImpl implements OrderRepository {
required Map<String, dynamic> deliveryAddress, required Map<String, dynamic> deliveryAddress,
required String paymentMethod, required String paymentMethod,
bool needsInvoice = false, bool needsInvoice = false,
bool needsNegotiation = false, bool ignorePricingRule = false,
bool contractRequest = false,
String? notes, String? notes,
}) async { }) async {
try { try {
@@ -107,7 +108,8 @@ class OrderRepositoryImpl implements OrderRepository {
deliveryAddress: deliveryAddress, deliveryAddress: deliveryAddress,
paymentMethod: paymentMethod, paymentMethod: paymentMethod,
needsInvoice: needsInvoice, needsInvoice: needsInvoice,
needsNegotiation: needsNegotiation, ignorePricingRule: ignorePricingRule,
contractRequest: contractRequest,
notes: notes, notes: notes,
); );
} catch (e) { } catch (e) {

View File

@@ -31,7 +31,8 @@ abstract class OrderRepository {
required Map<String, dynamic> deliveryAddress, required Map<String, dynamic> deliveryAddress,
required String paymentMethod, required String paymentMethod,
bool needsInvoice = false, bool needsInvoice = false,
bool needsNegotiation = false, bool ignorePricingRule = false,
bool contractRequest = false,
String? notes, String? notes,
}); });

View File

@@ -183,7 +183,7 @@ class OrderSuccessPage extends StatelessWidget {
// Navigate to order details page // Navigate to order details page
context.pushReplacementNamed( context.pushReplacementNamed(
RouteNames.orderDetail, RouteNames.orderDetail,
pathParameters: {'orderId': orderNumber}, pathParameters: {'id': orderNumber},
); );
}, },
icon: const FaIcon(FontAwesomeIcons.eye, size: 18), icon: const FaIcon(FontAwesomeIcons.eye, size: 18),

View File

@@ -31,7 +31,8 @@ Future<Map<String, dynamic>> createOrder(
required Map<String, dynamic> deliveryAddress, required Map<String, dynamic> deliveryAddress,
required String paymentMethod, required String paymentMethod,
bool needsInvoice = false, bool needsInvoice = false,
bool needsNegotiation = false, bool ignorePricingRule = false,
bool contractRequest = false,
String? notes, String? notes,
}) async { }) async {
final repository = await ref.watch(orderRepositoryProvider.future); final repository = await ref.watch(orderRepositoryProvider.future);
@@ -40,7 +41,8 @@ Future<Map<String, dynamic>> createOrder(
deliveryAddress: deliveryAddress, deliveryAddress: deliveryAddress,
paymentMethod: paymentMethod, paymentMethod: paymentMethod,
needsInvoice: needsInvoice, needsInvoice: needsInvoice,
needsNegotiation: needsNegotiation, ignorePricingRule: ignorePricingRule,
contractRequest: contractRequest,
notes: notes, notes: notes,
); );
} }

View File

@@ -83,7 +83,8 @@ final class CreateOrderProvider
Map<String, dynamic> deliveryAddress, Map<String, dynamic> deliveryAddress,
String paymentMethod, String paymentMethod,
bool needsInvoice, bool needsInvoice,
bool needsNegotiation, bool ignorePricingRule,
bool contractRequest,
String? notes, String? notes,
}) })
super.argument, super.argument,
@@ -120,7 +121,8 @@ final class CreateOrderProvider
Map<String, dynamic> deliveryAddress, Map<String, dynamic> deliveryAddress,
String paymentMethod, String paymentMethod,
bool needsInvoice, bool needsInvoice,
bool needsNegotiation, bool ignorePricingRule,
bool contractRequest,
String? notes, String? notes,
}); });
return createOrder( return createOrder(
@@ -129,7 +131,8 @@ final class CreateOrderProvider
deliveryAddress: argument.deliveryAddress, deliveryAddress: argument.deliveryAddress,
paymentMethod: argument.paymentMethod, paymentMethod: argument.paymentMethod,
needsInvoice: argument.needsInvoice, needsInvoice: argument.needsInvoice,
needsNegotiation: argument.needsNegotiation, ignorePricingRule: argument.ignorePricingRule,
contractRequest: argument.contractRequest,
notes: argument.notes, notes: argument.notes,
); );
} }
@@ -145,7 +148,7 @@ final class CreateOrderProvider
} }
} }
String _$createOrderHash() => r'2d13526815e19a2bbef2f2974dad991d8ffcb594'; String _$createOrderHash() => r'622a1d98d53a6696a302cde85842d449a8164fe7';
/// Create Order Provider /// Create Order Provider
/// ///
@@ -160,7 +163,8 @@ final class CreateOrderFamily extends $Family
Map<String, dynamic> deliveryAddress, Map<String, dynamic> deliveryAddress,
String paymentMethod, String paymentMethod,
bool needsInvoice, bool needsInvoice,
bool needsNegotiation, bool ignorePricingRule,
bool contractRequest,
String? notes, String? notes,
}) })
> { > {
@@ -182,7 +186,8 @@ final class CreateOrderFamily extends $Family
required Map<String, dynamic> deliveryAddress, required Map<String, dynamic> deliveryAddress,
required String paymentMethod, required String paymentMethod,
bool needsInvoice = false, bool needsInvoice = false,
bool needsNegotiation = false, bool ignorePricingRule = false,
bool contractRequest = false,
String? notes, String? notes,
}) => CreateOrderProvider._( }) => CreateOrderProvider._(
argument: ( argument: (
@@ -190,7 +195,8 @@ final class CreateOrderFamily extends $Family
deliveryAddress: deliveryAddress, deliveryAddress: deliveryAddress,
paymentMethod: paymentMethod, paymentMethod: paymentMethod,
needsInvoice: needsInvoice, needsInvoice: needsInvoice,
needsNegotiation: needsNegotiation, ignorePricingRule: ignorePricingRule,
contractRequest: contractRequest,
notes: notes, notes: notes,
), ),
from: this, from: this,