fix(orders): Fix shipping rate recalculation and auto-selection
## Issues Fixed: ### 1. Shipping rates not recalculating when address changes ✅ **Problem:** - Change province → Rates stay the same - Query was cached incorrectly **Root Cause:** Query key only tracked country, state, postcode: ```ts queryKey: [..., shippingData.country, shippingData.state, shippingData.postcode] ``` But Rajaongkir and other plugins also need: - City (different rates per city) - Address (for some plugins) **Solution:** ```ts queryKey: [ ..., shippingData.country, shippingData.state, shippingData.city, // Added shippingData.postcode, shippingData.address_1 // Added ], staleTime: 0, // Always refetch when key changes ``` ### 2. First rate auto-selected but dropdown shows placeholder ✅ **Problem:** - Rates calculated → First rate used in total - But dropdown shows "Select shipping" - Confusing UX **Solution:** Added useEffect to auto-select first rate: ```ts useEffect(() => { if (shippingRates?.methods?.length > 0) { const firstRateId = shippingRates.methods[0].id; const currentExists = shippingRates.methods.some(m => m.id === shippingMethod); // Auto-select if no selection or current not in new rates if (!shippingMethod || !currentExists) { setShippingMethod(firstRateId); } } }, [shippingRates?.methods]); ``` ## Benefits: - ✅ Change province → Rates recalculate immediately - ✅ First rate auto-selected in dropdown - ✅ Selection cleared if no rates available - ✅ Selection preserved if still valid after recalculation ## Testing: 1. Select Jakarta → Shows JNE rates 2. Change to Bali → Rates recalculate, first auto-selected 3. Change to remote area → Different rates, first auto-selected 4. Dropdown always shows current selection
This commit is contained in:
@@ -187,7 +187,7 @@ export default function OrderForm({
|
|||||||
|
|
||||||
// Calculate shipping rates dynamically
|
// Calculate shipping rates dynamically
|
||||||
const { data: shippingRates, isLoading: shippingLoading } = useQuery({
|
const { data: shippingRates, isLoading: shippingLoading } = useQuery({
|
||||||
queryKey: ['shipping-rates', items.map(i => ({ product_id: i.product_id, qty: i.qty })), shippingData.country, shippingData.postcode, shippingData.state],
|
queryKey: ['shipping-rates', items.map(i => ({ product_id: i.product_id, qty: i.qty })), shippingData.country, shippingData.state, shippingData.city, shippingData.postcode, shippingData.address_1],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (!shippingData.country) return null;
|
if (!shippingData.country) return null;
|
||||||
return api.post('/shipping/calculate', {
|
return api.post('/shipping/calculate', {
|
||||||
@@ -196,11 +196,12 @@ export default function OrderForm({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
enabled: !!shippingData.country && items.length > 0,
|
enabled: !!shippingData.country && items.length > 0,
|
||||||
|
staleTime: 0, // Always refetch when query key changes
|
||||||
});
|
});
|
||||||
|
|
||||||
// Calculate order preview with taxes
|
// Calculate order preview with taxes
|
||||||
const { data: orderPreview, isLoading: previewLoading } = useQuery({
|
const { data: orderPreview, isLoading: previewLoading } = useQuery({
|
||||||
queryKey: ['order-preview', items.map(i => ({ product_id: i.product_id, qty: i.qty })), bCountry, bState, bPost, bCity, shippingData, shippingMethod, validatedCoupons.map(c => c.code)],
|
queryKey: ['order-preview', items.map(i => ({ product_id: i.product_id, qty: i.qty })), bCountry, bState, bPost, bCity, shippingData.country, shippingData.state, shippingData.city, shippingData.postcode, shippingMethod, validatedCoupons.map(c => c.code)],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (items.length === 0) return null;
|
if (items.length === 0) return null;
|
||||||
return api.post('/orders/preview', {
|
return api.post('/orders/preview', {
|
||||||
@@ -212,6 +213,7 @@ export default function OrderForm({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
enabled: items.length > 0 && !!bCountry,
|
enabled: items.length > 0 && !!bCountry,
|
||||||
|
staleTime: 0, // Always refetch when query key changes
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Product search for Add Item ---
|
// --- Product search for Add Item ---
|
||||||
@@ -301,6 +303,21 @@ export default function OrderForm({
|
|||||||
setValidatedCoupons(validatedCoupons.filter(c => c.code !== code));
|
setValidatedCoupons(validatedCoupons.filter(c => c.code !== code));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Auto-select first shipping rate when rates change
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (shippingRates?.methods && shippingRates.methods.length > 0) {
|
||||||
|
const firstRateId = shippingRates.methods[0].id;
|
||||||
|
// Only auto-select if no method selected or current method not in new rates
|
||||||
|
const currentMethodExists = shippingRates.methods.some((m: any) => m.id === shippingMethod);
|
||||||
|
if (!shippingMethod || !currentMethodExists) {
|
||||||
|
setShippingMethod(firstRateId);
|
||||||
|
}
|
||||||
|
} else if (shippingRates?.methods && shippingRates.methods.length === 0) {
|
||||||
|
// Clear selection if no rates available
|
||||||
|
setShippingMethod('');
|
||||||
|
}
|
||||||
|
}, [shippingRates?.methods]);
|
||||||
|
|
||||||
// Check if cart has physical products
|
// Check if cart has physical products
|
||||||
const hasPhysicalProduct = React.useMemo(
|
const hasPhysicalProduct = React.useMemo(
|
||||||
() => items.some(item => {
|
() => items.some(item => {
|
||||||
|
|||||||
Reference in New Issue
Block a user