diff --git a/customer-spa/src/pages/Account/OrderDetails.tsx b/customer-spa/src/pages/Account/OrderDetails.tsx index 6da031f..72df5a5 100644 --- a/customer-spa/src/pages/Account/OrderDetails.tsx +++ b/customer-spa/src/pages/Account/OrderDetails.tsx @@ -12,6 +12,13 @@ interface OrderItem { image?: string; } +interface ShippingLine { + id: number; + method_title: string; + method_id: string; + total: string; +} + interface Order { id: number; order_number: string; @@ -26,6 +33,11 @@ interface Order { shipping: any; payment_method_title: string; needs_shipping: boolean; + shipping_lines?: ShippingLine[]; + // Tracking info (may be added by shipping plugins) + tracking_number?: string; + tracking_url?: string; + meta_data?: Array<{ key: string; value: string }>; } export default function OrderDetails() { @@ -100,7 +112,7 @@ export default function OrderDetails() { Back to Orders - +

Order #{order.order_number}

@@ -211,6 +223,59 @@ export default function OrderDetails() { {order.payment_method_title || 'Not specified'}
+ + {/* Shipping Method - only for physical product orders */} + {order.needs_shipping && order.shipping_lines && order.shipping_lines.length > 0 && ( +
+
+

Shipping Method

+
+
+ {order.shipping_lines.map((line) => ( +
+ {line.method_title} + {line.total} +
+ ))} + + {/* AWB Tracking - show for processing or completed orders */} + {(order.status === 'processing' || order.status === 'completed') && ( +
+ {order.tracking_number ? ( +
+
+ Tracking Number + {order.tracking_number} +
+ {order.tracking_url ? ( + + + + + + Track Shipment + + ) : ( +

+ Use the tracking number above to track your shipment on your courier's website. +

+ )} +
+ ) : ( +
+

Your order is being processed. Tracking information will be available once your order has been shipped.

+
+ )} +
+ )} +
+
+ )} ); } diff --git a/customer-spa/src/pages/Checkout/index.tsx b/customer-spa/src/pages/Checkout/index.tsx index 2e94eae..ccc741c 100644 --- a/customer-spa/src/pages/Checkout/index.tsx +++ b/customer-spa/src/pages/Checkout/index.tsx @@ -194,13 +194,25 @@ export default function Checkout() { // Initialize custom field values with defaults const customDefaults: Record = {}; data.fields.forEach(field => { - if (field.custom && field.default) { + if (field.default) { customDefaults[field.key] = field.default; } }); if (Object.keys(customDefaults).length > 0) { setCustomFieldData(prev => ({ ...customDefaults, ...prev })); } + + // Set billing default values for hidden fields (e.g., Indonesia-only stores) + const billingCountryField = data.fields.find(f => f.key === 'billing_country'); + if (billingCountryField?.type === 'hidden' && billingCountryField.default) { + setBillingData(prev => ({ ...prev, country: billingCountryField.default || prev.country })); + } + + // Set shipping default values for hidden fields + const shippingCountryField = data.fields.find(f => f.key === 'shipping_country'); + if (shippingCountryField?.type === 'hidden' && shippingCountryField.default) { + setShippingData(prev => ({ ...prev, country: shippingCountryField.default || prev.country })); + } } } catch (error) { console.error('Failed to load checkout fields:', error); @@ -210,6 +222,12 @@ export default function Checkout() { loadCheckoutFields(); }, [cart.items, isVirtualOnly]); + // Helper to check if a standard field should be hidden (set to type: 'hidden' in PHP) + const isFieldHidden = (fieldKey: string): boolean => { + const field = checkoutFields.find(f => f.key === fieldKey); + return field?.type === 'hidden'; + }; + // Filter custom fields by fieldset const billingCustomFields = checkoutFields.filter(f => f.fieldset === 'billing' && f.custom && !f.hidden); const shippingCustomFields = checkoutFields.filter(f => f.fieldset === 'shipping' && f.custom && !f.hidden); @@ -705,45 +723,54 @@ export default function Checkout() { className="w-full border rounded-lg px-4 py-2" /> -
- - setBillingData({ ...billingData, city: e.target.value })} - className="w-full border rounded-lg px-4 py-2" - /> -
-
- - setBillingData({ ...billingData, country: v })} - placeholder="Select country" - disabled={countries.length === 1} - /> -
-
- - {billingStateOptions.length > 0 ? ( - setBillingData({ ...billingData, state: v })} - placeholder="Select state" - /> - ) : ( + {/* City field - hidden if PHP sets type to 'hidden' */} + {!isFieldHidden('billing_city') && ( +
+ setBillingData({ ...billingData, state: e.target.value })} - placeholder="Enter state/province" + required + value={billingData.city} + onChange={(e) => setBillingData({ ...billingData, city: e.target.value })} className="w-full border rounded-lg px-4 py-2" /> - )} -
+
+ )} + {/* Country field - hidden if PHP sets type to 'hidden' */} + {!isFieldHidden('billing_country') && ( +
+ + setBillingData({ ...billingData, country: v })} + placeholder="Select country" + disabled={countries.length === 1} + /> +
+ )} + {/* State field - hidden if PHP sets type to 'hidden' */} + {!isFieldHidden('billing_state') && ( +
+ + {billingStateOptions.length > 0 ? ( + setBillingData({ ...billingData, state: v })} + placeholder="Select state" + /> + ) : ( + setBillingData({ ...billingData, state: e.target.value })} + placeholder="Enter state/province" + className="w-full border rounded-lg px-4 py-2" + /> + )} +
+ )}
-
- - setShippingData({ ...shippingData, city: e.target.value })} - className="w-full border rounded-lg px-4 py-2" - /> -
-
- - setShippingData({ ...shippingData, country: v })} - placeholder="Select country" - disabled={countries.length === 1} - /> -
-
- - {shippingStateOptions.length > 0 ? ( - setShippingData({ ...shippingData, state: v })} - placeholder="Select state" - /> - ) : ( + {/* City field - hidden if PHP sets type to 'hidden' */} + {!isFieldHidden('shipping_city') && ( +
+ setShippingData({ ...shippingData, state: e.target.value })} - placeholder="Enter state/province" + required + value={shippingData.city} + onChange={(e) => setShippingData({ ...shippingData, city: e.target.value })} className="w-full border rounded-lg px-4 py-2" /> - )} -
+
+ )} + {/* Country field - hidden if PHP sets type to 'hidden' */} + {!isFieldHidden('shipping_country') && ( +
+ + setShippingData({ ...shippingData, country: v })} + placeholder="Select country" + disabled={countries.length === 1} + /> +
+ )} + {/* State field - hidden if PHP sets type to 'hidden' */} + {!isFieldHidden('shipping_state') && ( +
+ + {shippingStateOptions.length > 0 ? ( + setShippingData({ ...shippingData, state: v })} + placeholder="Select state" + /> + ) : ( + setShippingData({ ...shippingData, state: e.target.value })} + placeholder="Enter state/province" + className="w-full border rounded-lg px-4 py-2" + /> + )} +
+ )}
cart; + // Calculate totals to ensure discounts are computed + $cart->calculate_totals(); + + // Format coupons with discount amounts + $coupons_with_discounts = []; + foreach ($cart->get_applied_coupons() as $coupon_code) { + $coupon = new \WC_Coupon($coupon_code); + $discount = $cart->get_coupon_discount_amount($coupon_code); + $coupons_with_discounts[] = [ + 'code' => $coupon_code, + 'discount' => (float) $discount, + 'type' => $coupon->get_discount_type(), + ]; + } + return new WP_REST_Response([ 'items' => $this->format_cart_items($cart->get_cart()), 'totals' => [ @@ -145,7 +160,8 @@ class CartController extends WP_REST_Controller { 'total' => $cart->get_total(''), 'total_tax' => $cart->get_total_tax(), ], - 'coupons' => $cart->get_applied_coupons(), + 'coupons' => $coupons_with_discounts, + 'discount_total' => (float) $cart->get_discount_total(), // Root level for frontend 'needs_shipping' => $cart->needs_shipping(), 'needs_payment' => $cart->needs_payment(), 'item_count' => $cart->get_cart_contents_count(),