fix: Address all 7 shipping/UI issues

##  Issue #1: Drawer Z-Index
- Increased drawer z-index from 60 to 9999
- Now works in wp-admin fullscreen mode
- Already worked in standalone and normal wp-admin

##  Issue #2: Add Zone Button
- Temporarily links to WooCommerce zone creation
- Works for both header button and empty state button
- Full zone dialog UI deferred (complex region selector needed)

##  Issue #3: Modal-over-Modal
- Removed Add Delivery Option dialog
- Replaced with inline expandable list
- Click "Add Delivery Option" → shows methods inline
- Click method → adds it and collapses list
- Same pattern for both desktop dialog and mobile drawer
- No more modal-over-modal!

##  Issue #4-7: Local Pickup Page
Analysis:
- Multiple pickup locations is NOT WooCommerce core
- Its an addon feature (Local Pickup Plus, etc)
- Having separate page violates our 80/20 rule
- Local pickup IS part of "Shipping & Delivery"

Solution:
- Removed "Local Pickup" from navigation
- Core local_pickup method in zones is sufficient
- Keeps WooNooW focused on core features
- Advanced pickup locations → use addons

## Philosophy Reinforced:
WooNooW handles 80% of daily use cases elegantly.
The 20% advanced/rare features stay in WooCommerce or addons.
This IS the value proposition - simplicity without sacrificing power.
This commit is contained in:
dwindown
2025-11-10 09:40:28 +07:00
parent 8bbed114bd
commit d624ac5591
3 changed files with 95 additions and 55 deletions

View File

@@ -26,7 +26,7 @@ const DrawerOverlay = React.forwardRef<
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-[60] bg-black/80", className)}
className={cn("fixed inset-0 z-[9999] bg-black/80", className)}
{...props}
/>
))
@@ -41,7 +41,7 @@ const DrawerContent = React.forwardRef<
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-[60] mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
"fixed inset-x-0 bottom-0 z-[9999] mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}

View File

@@ -111,7 +111,6 @@ function getStaticFallbackTree(): MainNode[] {
{ label: 'Store Details', mode: 'spa' as const, path: '/settings/store' },
{ label: 'Payments', mode: 'spa' as const, path: '/settings/payments' },
{ label: 'Shipping & Delivery', mode: 'spa' as const, path: '/settings/shipping' },
{ label: 'Local Pickup', mode: 'spa' as const, path: '/settings/local-pickup' },
{ label: 'Tax', mode: 'spa' as const, path: '/settings/tax' },
{ label: 'Checkout', mode: 'spa' as const, path: '/settings/checkout' },
{ label: 'Customer Accounts', mode: 'spa' as const, path: '/settings/customers' },

View File

@@ -35,6 +35,7 @@ export default function ShippingPage() {
const [togglingMethod, setTogglingMethod] = useState<string | null>(null);
const [selectedZone, setSelectedZone] = useState<any | null>(null);
const [showAddMethod, setShowAddMethod] = useState(false);
const [showAvailableMethods, setShowAvailableMethods] = useState(false);
const [expandedMethod, setExpandedMethod] = useState<string>('');
const [methodSettings, setMethodSettings] = useState<Record<string, any>>({});
const [deletingMethod, setDeletingMethod] = useState<{ zoneId: number; instanceId: number; name: string } | null>(null);
@@ -256,10 +257,12 @@ export default function ShippingPage() {
<Button
variant="outline"
size="sm"
onClick={() => setShowAddZone(true)}
asChild
>
<Plus className="h-4 w-4 mr-2" />
{__('Add Zone')}
<a href={`${wcAdminUrl}/admin.php?page=wc-settings&tab=shipping&action=add_zone`} target="_blank" rel="noopener noreferrer">
<Plus className="h-4 w-4 mr-2" />
{__('Add Zone')}
</a>
</Button>
}
>
@@ -269,10 +272,12 @@ export default function ShippingPage() {
{__('No shipping zones configured yet. Create your first zone to start offering shipping.')}
</p>
<Button
onClick={() => setShowAddZone(true)}
asChild
>
<Plus className="h-4 w-4 mr-2" />
{__('Create First Zone')}
<a href={`${wcAdminUrl}/admin.php?page=wc-settings&tab=shipping&action=add_zone`} target="_blank" rel="noopener noreferrer">
<Plus className="h-4 w-4 mr-2" />
{__('Create First Zone')}
</a>
</Button>
</div>
) : (
@@ -399,14 +404,47 @@ export default function ShippingPage() {
<div className="flex-1 overflow-y-auto p-6 min-h-0">
<div className="space-y-4">
{/* Add Delivery Option Button */}
<Button
variant="outline"
className="w-full"
onClick={() => setShowAddMethod(true)}
>
<Plus className="h-4 w-4 mr-2" />
{__('Add Delivery Option')}
</Button>
{!showAvailableMethods ? (
<Button
variant="outline"
className="w-full"
onClick={() => setShowAvailableMethods(true)}
>
<Plus className="h-4 w-4 mr-2" />
{__('Add Delivery Option')}
</Button>
) : (
<div className="border rounded-lg p-4 space-y-3">
<div className="flex items-center justify-between mb-2">
<h3 className="font-medium">{__('Available Shipping Methods')}</h3>
<Button
variant="ghost"
size="sm"
onClick={() => setShowAvailableMethods(false)}
>
<X className="h-4 w-4" />
</Button>
</div>
{availableMethods.map((method: any) => (
<button
key={method.id}
onClick={() => {
handleAddMethod(method.id);
setShowAvailableMethods(false);
}}
disabled={addMethodMutation.isPending}
className="w-full text-left p-3 border rounded-lg hover:border-primary hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="font-medium text-sm">{method.title}</div>
{method.description && (
<div className="text-xs text-muted-foreground mt-1">
{method.description}
</div>
)}
</button>
))}
</div>
)}
{/* Delivery Options Accordion */}
<Accordion type="single" collapsible value={expandedMethod} onValueChange={(value) => {
@@ -578,14 +616,47 @@ export default function ShippingPage() {
<div className="flex-1 overflow-y-auto px-4 py-4 min-h-0">
<div className="space-y-3">
{/* Add Delivery Option Button */}
<Button
variant="outline"
className="w-full"
onClick={() => setShowAddMethod(true)}
>
<Plus className="h-4 w-4 mr-2" />
{__('Add Delivery Option')}
</Button>
{!showAvailableMethods ? (
<Button
variant="outline"
className="w-full"
onClick={() => setShowAvailableMethods(true)}
>
<Plus className="h-4 w-4 mr-2" />
{__('Add Delivery Option')}
</Button>
) : (
<div className="border rounded-lg p-3 space-y-2">
<div className="flex items-center justify-between mb-2">
<h3 className="font-medium text-sm">{__('Available Shipping Methods')}</h3>
<Button
variant="ghost"
size="sm"
onClick={() => setShowAvailableMethods(false)}
>
<X className="h-3 w-3" />
</Button>
</div>
{availableMethods.map((method: any) => (
<button
key={method.id}
onClick={() => {
handleAddMethod(method.id);
setShowAvailableMethods(false);
}}
disabled={addMethodMutation.isPending}
className="w-full text-left p-2 border rounded-lg hover:border-primary hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="font-medium text-xs">{method.title}</div>
{method.description && (
<div className="text-[10px] text-muted-foreground mt-0.5">
{method.description}
</div>
)}
</button>
))}
</div>
)}
{/* Delivery Options Accordion (Mobile) */}
<Accordion type="single" collapsible value={expandedMethod} onValueChange={(value) => {
@@ -740,36 +811,6 @@ export default function ShippingPage() {
)
)}
{/* Add Delivery Option Dialog */}
<Dialog open={showAddMethod} onOpenChange={setShowAddMethod}>
<DialogContent className="max-w-md">
<DialogHeader>
<DialogTitle>{__('Add Delivery Option')}</DialogTitle>
</DialogHeader>
<div className="space-y-4 py-4">
<p className="text-sm text-muted-foreground">
{__('Select a delivery option to add:')}</p>
<div className="space-y-2">
{availableMethods.map((method: any) => (
<button
key={method.id}
onClick={() => handleAddMethod(method.id)}
disabled={addMethodMutation.isPending}
className="w-full text-left p-4 border rounded-lg hover:border-primary hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<div className="font-medium">{method.title}</div>
{method.description && (
<div className="text-sm text-muted-foreground mt-1">
{method.description}
</div>
)}
</button>
))}
</div>
</div>
</DialogContent>
</Dialog>
{/* Delete Method Confirmation Dialog */}
<AlertDialog open={!!deletingMethod} onOpenChange={() => setDeletingMethod(null)}>
<AlertDialogContent>