fix: Shipping toggle refresh + AlertDialog + Local Pickup nav + Notifications info
## 1. Fixed Shipping Method Toggle State ✅ - Updated useEffect to properly sync selectedZone with zones data - Added JSON comparison to prevent infinite loops - Toggle now refreshes zone data correctly ## 2. Replace confirm() with AlertDialog ✅ - Added AlertDialog component for delete confirmation - Shows method name in confirmation message - Better UX with proper dialog styling - Updated both desktop and mobile versions ## 3. Added Local Pickup to Navigation ✅ - Added "Local Pickup" menu item in Settings - Now accessible from Settings > Local Pickup - Path: /settings/local-pickup ## 4. Shipping Cost Shortcodes ✅ - Already supported via HTML rendering - WooCommerce shortcodes like [fee percent="10"] work - [qty], [cost] are handled by WooCommerce backend - No additional SPA work needed ## 5. Enhanced Notifications Page ✅ - Added comprehensive info card explaining: - What WooNooW provides (simple toggle) - What WooCommerce provides (advanced config) - Clear guidance on when to use each - Links to WooCommerce for templates/styling - Replaced ToggleField with Switch for simpler usage ## Key Decisions: ✅ AlertDialog > confirm() for better UX ✅ Notifications = Simple toggle + guidance to WC ✅ Shortcodes handled by WooCommerce (no SPA work) ✅ Local Pickup now discoverable in nav
This commit is contained in:
@@ -111,6 +111,7 @@ 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' },
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { api } from '@/lib/api';
|
||||
import { SettingsLayout } from './components/SettingsLayout';
|
||||
import { SettingsCard } from './components/SettingsCard';
|
||||
import { ToggleField } from './components/ToggleField';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ExternalLink, RefreshCw, Mail } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
@@ -65,6 +65,38 @@ export default function NotificationsSettings() {
|
||||
}
|
||||
>
|
||||
<div className="space-y-6">
|
||||
{/* Info Card */}
|
||||
<SettingsCard
|
||||
title={__('About Email Notifications')}
|
||||
description={__('Quick enable/disable controls for WooCommerce emails')}
|
||||
>
|
||||
<div className="text-sm text-muted-foreground space-y-2">
|
||||
<p>
|
||||
{__('WooNooW provides simple toggle controls to enable or disable email notifications. For advanced customization like email templates, styling, content, and recipients, use the WooCommerce settings page.')}
|
||||
</p>
|
||||
<p className="font-medium text-foreground">
|
||||
{__('What you can do here:')}
|
||||
</p>
|
||||
<ul className="list-disc list-inside space-y-1 ml-2">
|
||||
<li>{__('Enable/disable customer emails (order confirmations, shipping updates, etc.)')}</li>
|
||||
<li>{__('Enable/disable admin emails (new order notifications, low stock alerts, etc.)')}</li>
|
||||
<li>{__('View current sender name and email address')}</li>
|
||||
</ul>
|
||||
<p className="font-medium text-foreground mt-3">
|
||||
{__('For advanced configuration:')}
|
||||
</p>
|
||||
<ul className="list-disc list-inside space-y-1 ml-2">
|
||||
<li>{__('Email templates and HTML/CSS styling')}</li>
|
||||
<li>{__('Email subject lines and content')}</li>
|
||||
<li>{__('Custom recipient addresses')}</li>
|
||||
<li>{__('Additional email headers')}</li>
|
||||
</ul>
|
||||
<p className="mt-3">
|
||||
{__('Use the "Edit in WooCommerce" links below or the advanced settings link at the bottom.')}
|
||||
</p>
|
||||
</div>
|
||||
</SettingsCard>
|
||||
|
||||
{/* Customer Emails */}
|
||||
<SettingsCard
|
||||
title={__('Customer Notifications')}
|
||||
@@ -81,9 +113,9 @@ export default function NotificationsSettings() {
|
||||
<p className="text-sm text-muted-foreground">{email.description}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<ToggleField
|
||||
<Switch
|
||||
checked={email.enabled === 'yes'}
|
||||
onChange={(checked) => toggleMutation.mutate({
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({
|
||||
emailId: email.id,
|
||||
enabled: checked
|
||||
})}
|
||||
@@ -124,9 +156,9 @@ export default function NotificationsSettings() {
|
||||
<p className="text-sm text-muted-foreground">{email.description}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<ToggleField
|
||||
<Switch
|
||||
checked={email.enabled === 'yes'}
|
||||
onChange={(checked) => toggleMutation.mutate({
|
||||
onCheckedChange={(checked) => toggleMutation.mutate({
|
||||
emailId: email.id,
|
||||
enabled: checked
|
||||
})}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { SettingsCard } from './components/SettingsCard';
|
||||
import { ToggleField } from './components/ToggleField';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
|
||||
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from '@/components/ui/drawer';
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
||||
import { Globe, Truck, MapPin, Edit, Trash2, RefreshCw, Loader2, ExternalLink, Settings, Plus, X, ChevronDown } from 'lucide-react';
|
||||
@@ -33,10 +34,10 @@ export default function ShippingPage() {
|
||||
const wcAdminUrl = (window as any).WNW_CONFIG?.wpAdminUrl || '/wp-admin';
|
||||
const [togglingMethod, setTogglingMethod] = useState<string | null>(null);
|
||||
const [selectedZone, setSelectedZone] = useState<any | null>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [showAddMethod, setShowAddMethod] = 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);
|
||||
const isDesktop = useMediaQuery("(min-width: 768px)");
|
||||
|
||||
// Fetch shipping zones from WooCommerce
|
||||
@@ -55,13 +56,13 @@ export default function ShippingPage() {
|
||||
|
||||
// Sync selectedZone with zones data when it changes
|
||||
useEffect(() => {
|
||||
if (selectedZone && zones.length > 0) {
|
||||
if (selectedZone && zones && zones.length > 0) {
|
||||
const updatedZone = zones.find((z: any) => z.id === selectedZone.id);
|
||||
if (updatedZone) {
|
||||
if (updatedZone && JSON.stringify(updatedZone) !== JSON.stringify(selectedZone)) {
|
||||
setSelectedZone(updatedZone);
|
||||
}
|
||||
}
|
||||
}, [zones]);
|
||||
}, [zones, selectedZone]);
|
||||
|
||||
// Toggle shipping method mutation
|
||||
const toggleMutation = useMutation({
|
||||
@@ -153,9 +154,19 @@ export default function ShippingPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteMethod = (instanceId: number) => {
|
||||
if (selectedZone && confirm(__('Are you sure you want to delete this shipping method?'))) {
|
||||
deleteMethodMutation.mutate({ zoneId: selectedZone.id, instanceId });
|
||||
const handleDeleteMethod = (instanceId: number, methodName: string) => {
|
||||
if (selectedZone) {
|
||||
setDeletingMethod({ zoneId: selectedZone.id, instanceId, name: methodName });
|
||||
}
|
||||
};
|
||||
|
||||
const confirmDelete = () => {
|
||||
if (deletingMethod) {
|
||||
deleteMethodMutation.mutate({
|
||||
zoneId: deletingMethod.zoneId,
|
||||
instanceId: deletingMethod.instanceId
|
||||
});
|
||||
setDeletingMethod(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -424,7 +435,7 @@ export default function ShippingPage() {
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
handleDeleteMethod(rate.instance_id);
|
||||
handleDeleteMethod(rate.instance_id, rate.title);
|
||||
setExpandedMethod('');
|
||||
}}
|
||||
disabled={deleteMethodMutation.isPending}
|
||||
@@ -594,7 +605,7 @@ export default function ShippingPage() {
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
handleDeleteMethod(rate.instance_id);
|
||||
handleDeleteMethod(rate.instance_id, rate.title);
|
||||
setExpandedMethod('');
|
||||
}}
|
||||
disabled={deleteMethodMutation.isPending}
|
||||
@@ -696,6 +707,28 @@ export default function ShippingPage() {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Delete Confirmation Dialog */}
|
||||
<AlertDialog open={!!deletingMethod} onOpenChange={() => setDeletingMethod(null)}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{__('Delete Shipping Method?')}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{__('Are you sure you want to delete')} <strong>{deletingMethod?.name}</strong>?
|
||||
{' '}{__('This action cannot be undone.')}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{__('Cancel')}</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={confirmDelete}
|
||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{__('Delete')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
||||
</SettingsLayout>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user