From 3d9af05a2513774e0e4158312d61a1cca567eed0 Mon Sep 17 00:00:00 2001 From: dwindown Date: Mon, 10 Nov 2025 09:58:28 +0700 Subject: [PATCH] feat: Complete Zone CRUD + fix terminology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## ✅ Issue #2: Zone CRUD Complete - Added full Add/Edit Zone dialog with region selector - Multi-select for countries/states/continents - Create, Update, Delete all working - NO MORE menu-ing WooCommerce! ## ✅ Issue #3: Terminology Fixed - Changed "Delivery Option" → "Shipping Method" everywhere - Fixed query enabled condition (showAvailableMethods) - Now methods list appears correctly ## UI Improvements: - 3 buttons per zone: Edit (pencil), Delete (trash), Settings (gear) - Edit = zone name/regions - Settings = manage methods - Clear separation of concerns --- admin-spa/src/routes/Settings/Shipping.tsx | 155 ++++++++++++++++++--- 1 file changed, 137 insertions(+), 18 deletions(-) diff --git a/admin-spa/src/routes/Settings/Shipping.tsx b/admin-spa/src/routes/Settings/Shipping.tsx index 436226f..71e86c3 100644 --- a/admin-spa/src/routes/Settings/Shipping.tsx +++ b/admin-spa/src/routes/Settings/Shipping.tsx @@ -55,7 +55,14 @@ export default function ShippingPage() { const { data: availableMethods = [] } = useQuery({ queryKey: ['available-shipping-methods'], queryFn: () => api.get('/settings/shipping/methods/available'), - enabled: showAddMethod, + enabled: showAvailableMethods, + }); + + // Fetch available locations (countries/states) for zone regions + const { data: availableLocations = [] } = useQuery({ + queryKey: ['available-locations'], + queryFn: () => api.get('/settings/shipping/locations'), + enabled: showAddZone || !!editingZone, }); // Sync selectedZone with zones data when it changes @@ -257,12 +264,10 @@ export default function ShippingPage() { } > @@ -272,12 +277,10 @@ export default function ShippingPage() { {__('No shipping zones configured yet. Create your first zone to start offering shipping.')}

) : ( @@ -306,7 +309,8 @@ export default function ShippingPage() { @@ -314,9 +318,18 @@ export default function ShippingPage() { variant="ghost" size="sm" onClick={() => setDeletingZone(zone)} + title={__('Delete zone')} > + @@ -403,7 +416,7 @@ export default function ShippingPage() {
- {/* Add Delivery Option Button */} + {/* Add Shipping Method Button */} {!showAvailableMethods ? ( ) : (
@@ -446,7 +459,7 @@ export default function ShippingPage() {
)} - {/* Delivery Options Accordion */} + {/* Shipping Methods Accordion */} { setExpandedMethod(value); if (value) { @@ -615,7 +628,7 @@ export default function ShippingPage() {
- {/* Add Delivery Option Button */} + {/* Add Shipping Method Button */} {!showAvailableMethods ? ( ) : (
@@ -658,7 +671,7 @@ export default function ShippingPage() {
)} - {/* Delivery Options Accordion (Mobile) */} + {/* Shipping Methods Accordion (Mobile) */} { setExpandedMethod(value); if (value) { @@ -859,6 +872,112 @@ export default function ShippingPage() { + {/* Add/Edit Zone Dialog */} + { + if (!open) { + setShowAddZone(false); + setEditingZone(null); + } + }}> + + + {editingZone ? __('Edit Zone') : __('Add Shipping Zone')} + +
{ + e.preventDefault(); + const formData = new FormData(e.currentTarget); + const zoneName = formData.get('name') as string; + const selectedRegions = formData.getAll('regions').map(code => { + const location = availableLocations.find((l: any) => l.code === code); + return location ? { code: location.code, type: location.type } : null; + }).filter(Boolean); + + if (editingZone) { + updateZoneMutation.mutate({ + zoneId: editingZone.id, + name: zoneName, + regions: selectedRegions, + }); + } else { + createZoneMutation.mutate({ + name: zoneName, + regions: selectedRegions, + }); + } + }} className="space-y-4"> +
+ + +
+ +
+ +

+ {__('Select countries, states, or continents for this zone')} +

+
+ {availableLocations.length === 0 ? ( +
+ {__('Loading locations...')} +
+ ) : ( +
+ {availableLocations.map((location: any) => ( + + ))} +
+ )} +
+
+ +
+ + +
+
+
+
+ ); }