feat: Tax route fix + Local Pickup + Email/Notifications settings

## 1. Fixed Tax Settings Route 
- Changed /settings/taxes → /settings/tax in nav tree
- Now matches App.tsx route
- Tax page now loads correctly

## 2. Advanced Local Pickup 
Frontend (LocalPickup.tsx):
- Add/edit/delete pickup locations
- Enable/disable locations
- Full address fields (street, city, state, postcode)
- Phone number and business hours
- Clean modal UI for adding locations

Backend (PickupLocationsController.php):
- GET /settings/pickup-locations
- POST /settings/pickup-locations (create)
- POST /settings/pickup-locations/:id (update)
- DELETE /settings/pickup-locations/:id
- POST /settings/pickup-locations/:id/toggle
- Stores in wp_options as array

## 3. Email/Notifications Settings 
Frontend (Notifications.tsx):
- List all WooCommerce emails
- Separate customer vs admin emails
- Enable/disable toggle for each email
- Show from name/email
- Link to WooCommerce for advanced config

Backend (EmailController.php):
- GET /settings/emails - List all emails
- POST /settings/emails/:id/toggle - Enable/disable
- Uses WC()->mailer()->get_emails()
- Auto-detects recipient type (customer/admin)

## Features:
 Simple, non-tech-savvy UI
 All CRUD operations
 Real-time updates
 Links to WooCommerce for advanced settings
 Mobile responsive

Next: Test all settings pages
This commit is contained in:
dwindown
2025-11-09 23:44:24 +07:00
parent 603d94b73c
commit 5fb5eda9c3
7 changed files with 1009 additions and 2 deletions

View File

@@ -0,0 +1,228 @@
import React from 'react';
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 { Button } from '@/components/ui/button';
import { ExternalLink, RefreshCw, Mail } from 'lucide-react';
import { toast } from 'sonner';
import { __ } from '@/lib/i18n';
export default function NotificationsSettings() {
const queryClient = useQueryClient();
const wcAdminUrl = (window as any).WNW_CONFIG?.wpAdminUrl || '/wp-admin';
// Fetch email settings
const { data: settings, isLoading, refetch } = useQuery({
queryKey: ['email-settings'],
queryFn: () => api.get('/settings/emails'),
});
// Toggle email mutation
const toggleMutation = useMutation({
mutationFn: async ({ emailId, enabled }: { emailId: string; enabled: boolean }) => {
return api.post(`/settings/emails/${emailId}/toggle`, { enabled });
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['email-settings'] });
toast.success(__('Email settings updated'));
},
onError: (error: any) => {
toast.error(error?.message || __('Failed to update email settings'));
},
});
if (isLoading) {
return (
<SettingsLayout
title={__('Notifications')}
description={__('Manage email notifications sent to customers and admins')}
>
<div className="flex items-center justify-center py-12">
<RefreshCw className="h-6 w-6 animate-spin text-muted-foreground" />
</div>
</SettingsLayout>
);
}
const customerEmails = settings?.emails?.filter((e: any) => e.recipient === 'customer') || [];
const adminEmails = settings?.emails?.filter((e: any) => e.recipient === 'admin') || [];
return (
<SettingsLayout
title={__('Notifications')}
description={__('Manage email notifications sent to customers and admins')}
action={
<Button
variant="outline"
size="sm"
onClick={() => refetch()}
>
<RefreshCw className="h-4 w-4 mr-2" />
{__('Refresh')}
</Button>
}
>
<div className="space-y-6">
{/* Customer Emails */}
<SettingsCard
title={__('Customer Notifications')}
description={__('Emails sent to customers about their orders')}
>
<div className="space-y-4">
{customerEmails.map((email: any) => (
<div key={email.id} className="flex items-start justify-between py-3 border-b last:border-0">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Mail className="h-4 w-4 text-muted-foreground" />
<h3 className="font-medium">{email.title}</h3>
</div>
<p className="text-sm text-muted-foreground">{email.description}</p>
</div>
<div className="flex items-center gap-3">
<ToggleField
checked={email.enabled === 'yes'}
onChange={(checked) => toggleMutation.mutate({
emailId: email.id,
enabled: checked
})}
disabled={toggleMutation.isPending}
/>
<Button
variant="ghost"
size="sm"
asChild
>
<a
href={`${wcAdminUrl}/admin.php?page=wc-settings&tab=email&section=${email.id}`}
target="_blank"
rel="noopener noreferrer"
>
<ExternalLink className="h-4 w-4" />
</a>
</Button>
</div>
</div>
))}
</div>
</SettingsCard>
{/* Admin Emails */}
<SettingsCard
title={__('Admin Notifications')}
description={__('Emails sent to store administrators')}
>
<div className="space-y-4">
{adminEmails.map((email: any) => (
<div key={email.id} className="flex items-start justify-between py-3 border-b last:border-0">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Mail className="h-4 w-4 text-muted-foreground" />
<h3 className="font-medium">{email.title}</h3>
</div>
<p className="text-sm text-muted-foreground">{email.description}</p>
</div>
<div className="flex items-center gap-3">
<ToggleField
checked={email.enabled === 'yes'}
onChange={(checked) => toggleMutation.mutate({
emailId: email.id,
enabled: checked
})}
disabled={toggleMutation.isPending}
/>
<Button
variant="ghost"
size="sm"
asChild
>
<a
href={`${wcAdminUrl}/admin.php?page=wc-settings&tab=email&section=${email.id}`}
target="_blank"
rel="noopener noreferrer"
>
<ExternalLink className="h-4 w-4" />
</a>
</Button>
</div>
</div>
))}
</div>
</SettingsCard>
{/* Email Sender Settings */}
<SettingsCard
title={__('Email Sender')}
description={__('Configure who emails are sent from')}
>
<div className="space-y-3">
<div className="flex items-center justify-between py-2">
<div>
<p className="font-medium text-sm">{__('From Name')}</p>
<p className="text-xs text-muted-foreground">
{settings?.from_name || __('Not configured')}
</p>
</div>
<Button
variant="outline"
size="sm"
asChild
>
<a
href={`${wcAdminUrl}/admin.php?page=wc-settings&tab=email`}
target="_blank"
rel="noopener noreferrer"
>
{__('Change')}
</a>
</Button>
</div>
<div className="flex items-center justify-between py-2 border-t">
<div>
<p className="font-medium text-sm">{__('From Email')}</p>
<p className="text-xs text-muted-foreground">
{settings?.from_email || __('Not configured')}
</p>
</div>
<Button
variant="outline"
size="sm"
asChild
>
<a
href={`${wcAdminUrl}/admin.php?page=wc-settings&tab=email`}
target="_blank"
rel="noopener noreferrer"
>
{__('Change')}
</a>
</Button>
</div>
</div>
</SettingsCard>
{/* Advanced Settings Link */}
<div className="rounded-lg border border-dashed p-6 text-center">
<p className="text-sm text-muted-foreground mb-4">
{__('For email templates, styling, and advanced configuration, use the WooCommerce settings page')}
</p>
<Button
variant="outline"
asChild
>
<a
href={`${wcAdminUrl}/admin.php?page=wc-settings&tab=email`}
target="_blank"
rel="noopener noreferrer"
>
<ExternalLink className="h-4 w-4 mr-2" />
{__('Open Email Settings in WooCommerce')}
</a>
</Button>
</div>
</div>
</SettingsLayout>
);
}