diff --git a/admin-spa/src/routes/Orders/partials/OrderForm.tsx b/admin-spa/src/routes/Orders/partials/OrderForm.tsx index e45bae9..8347c6f 100644 --- a/admin-spa/src/routes/Orders/partials/OrderForm.tsx +++ b/admin-spa/src/routes/Orders/partials/OrderForm.tsx @@ -133,15 +133,9 @@ export default function OrderForm({ const [bCountry, setBCountry] = React.useState(initial?.billing?.country || baseCountry); const [bState, setBState] = React.useState(initial?.billing?.state || ''); - // Shipping toggle + fields + // Shipping toggle + dynamic fields const [shipDiff, setShipDiff] = React.useState(Boolean(initial?.shipping && !isEmptyAddress(initial?.shipping))); - const [sFirst, setSFirst] = React.useState(initial?.shipping?.first_name || ''); - const [sLast, setSLast] = React.useState(initial?.shipping?.last_name || ''); - const [sAddr1, setSAddr1] = React.useState(initial?.shipping?.address_1 || ''); - const [sCity, setSCity] = React.useState(initial?.shipping?.city || ''); - const [sPost, setSPost] = React.useState(initial?.shipping?.postcode || ''); - const [sCountry, setSCountry] = React.useState(initial?.shipping?.country || bCountry); - const [sState, setSState] = React.useState(initial?.shipping?.state || ''); + const [shippingData, setShippingData] = React.useState>(initial?.shipping || {}); // If store sells to a single country, force-select it for billing & shipping React.useEffect(() => { @@ -177,6 +171,18 @@ export default function OrderForm({ const [validatedCoupons, setValidatedCoupons] = React.useState([]); const [couponValidating, setCouponValidating] = React.useState(false); + // Fetch dynamic checkout fields based on cart items + const { data: checkoutFields } = useQuery({ + queryKey: ['checkout-fields', items.map(i => ({ product_id: i.product_id, qty: i.qty }))], + queryFn: async () => { + if (items.length === 0) return null; + return api.post('/checkout/fields', { + items: items.map(i => ({ product_id: i.product_id, qty: i.qty })), + }); + }, + enabled: items.length > 0, + }); + // --- Product search for Add Item --- const [searchQ, setSearchQ] = React.useState(''); const [customerSearchQ, setCustomerSearchQ] = React.useState(''); @@ -324,15 +330,7 @@ export default function OrderForm({ const payload: OrderPayload = { status, billing: billingData, - shipping: shipDiff && hasPhysicalProduct ? { - first_name: sFirst, - last_name: sLast, - address_1: sAddr1, - city: sCity, - state: sState, - postcode: sPost, - country: sCountry, - } : undefined, + shipping: shipDiff && hasPhysicalProduct ? shippingData : undefined, payment_method: paymentMethod || undefined, shipping_method: shippingMethod || undefined, customer_note: note || undefined, @@ -803,54 +801,65 @@ export default function OrderForm({ )} - {/* Shipping address */} - {hasPhysicalProduct && shipDiff && ( + {/* Shipping address - Dynamic Fields */} + {hasPhysicalProduct && shipDiff && checkoutFields?.fields && (

{__('Shipping address')}

-
- - setSFirst(e.target.value)} /> -
-
- - setSLast(e.target.value)} /> -
-
- - setSAddr1(e.target.value)} /> -
-
- - setSCity(e.target.value)} /> -
-
- - setSPost(e.target.value)} /> -
-
- - -
-
- - -
+ {checkoutFields.fields + .filter((f: any) => f.fieldset === 'shipping' && !f.hidden) + .sort((a: any, b: any) => (a.priority || 0) - (b.priority || 0)) + .map((field: any) => { + const isWide = ['address_1', 'address_2'].includes(field.key.replace('shipping_', '')); + const fieldKey = field.key.replace('shipping_', ''); + + return ( +
+ + {field.type === 'select' && field.options ? ( + + ) : field.key === 'shipping_country' ? ( + setShippingData({...shippingData, country: v})} + placeholder={field.placeholder || __('Select country')} + disabled={oneCountryOnly} + /> + ) : field.type === 'textarea' ? ( +