feat: Restructure Channel Configuration as separate section
✅ New Structure: Notifications ├── Staff Notifications (toggle only) ├── Customer Notifications (toggle only) ├── Channel Configuration (new section) │ ├── Email Configuration │ │ ├── Template Settings (colors, logo, branding) │ │ └── Connection Settings (wp_mail/SMTP) │ ├── Push Configuration │ │ ├── Template Settings (icon, badge, sound) │ │ └── Connection Settings (browser-native/FCM) │ └── Future: WhatsApp, Telegram, SMS (addons) └── Activity Log (coming soon) ✅ Separation of Concerns: - Staff/Customer pages: "What to send" (enable/disable) - Channel Config: "How to send" (global settings) ✅ Changes: - Created ChannelConfiguration.tsx (main page listing all channels) - Created EmailConfiguration.tsx (template + connection tabs) - Created PushConfiguration.tsx (template + connection tabs) - Updated Staff/Customer Channels tabs to toggle-only - Removed Configure buttons from Staff/Customer pages - Added links to Channel Configuration - Updated main Notifications page with new card - Added routing for all new pages ✅ Benefits: - Clear separation: enable vs configure - Global settings apply to both staff & customer - Scalable for addon channels - No confusion about where to configure - Consistent with app patterns 🎯 Ready for: WhatsApp, Telegram, SMS addons
This commit is contained in:
@@ -203,6 +203,9 @@ import SettingsLocalPickup from '@/routes/Settings/LocalPickup';
|
|||||||
import SettingsNotifications from '@/routes/Settings/Notifications';
|
import SettingsNotifications from '@/routes/Settings/Notifications';
|
||||||
import StaffNotifications from '@/routes/Settings/Notifications/Staff';
|
import StaffNotifications from '@/routes/Settings/Notifications/Staff';
|
||||||
import CustomerNotifications from '@/routes/Settings/Notifications/Customer';
|
import CustomerNotifications from '@/routes/Settings/Notifications/Customer';
|
||||||
|
import ChannelConfiguration from '@/routes/Settings/Notifications/ChannelConfiguration';
|
||||||
|
import EmailConfiguration from '@/routes/Settings/Notifications/EmailConfiguration';
|
||||||
|
import PushConfiguration from '@/routes/Settings/Notifications/PushConfiguration';
|
||||||
import EmailCustomization from '@/routes/Settings/Notifications/EmailCustomization';
|
import EmailCustomization from '@/routes/Settings/Notifications/EmailCustomization';
|
||||||
import EditTemplate from '@/routes/Settings/Notifications/EditTemplate';
|
import EditTemplate from '@/routes/Settings/Notifications/EditTemplate';
|
||||||
import SettingsDeveloper from '@/routes/Settings/Developer';
|
import SettingsDeveloper from '@/routes/Settings/Developer';
|
||||||
@@ -494,6 +497,9 @@ function AppRoutes() {
|
|||||||
<Route path="/settings/notifications" element={<SettingsNotifications />} />
|
<Route path="/settings/notifications" element={<SettingsNotifications />} />
|
||||||
<Route path="/settings/notifications/staff" element={<StaffNotifications />} />
|
<Route path="/settings/notifications/staff" element={<StaffNotifications />} />
|
||||||
<Route path="/settings/notifications/customer" element={<CustomerNotifications />} />
|
<Route path="/settings/notifications/customer" element={<CustomerNotifications />} />
|
||||||
|
<Route path="/settings/notifications/channels" element={<ChannelConfiguration />} />
|
||||||
|
<Route path="/settings/notifications/channels/email" element={<EmailConfiguration />} />
|
||||||
|
<Route path="/settings/notifications/channels/push" element={<PushConfiguration />} />
|
||||||
<Route path="/settings/notifications/email-customization" element={<EmailCustomization />} />
|
<Route path="/settings/notifications/email-customization" element={<EmailCustomization />} />
|
||||||
<Route path="/settings/notifications/edit-template" element={<EditTemplate />} />
|
<Route path="/settings/notifications/edit-template" element={<EditTemplate />} />
|
||||||
<Route path="/settings/brand" element={<SettingsIndex />} />
|
<Route path="/settings/brand" element={<SettingsIndex />} />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { SettingsLayout } from './components/SettingsLayout';
|
|||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { __ } from '@/lib/i18n';
|
import { __ } from '@/lib/i18n';
|
||||||
import { Bell, Users, ChevronRight, Activity, Palette } from 'lucide-react';
|
import { Bell, Users, ChevronRight, Activity, Settings } from 'lucide-react';
|
||||||
|
|
||||||
export default function NotificationsSettings() {
|
export default function NotificationsSettings() {
|
||||||
return (
|
return (
|
||||||
@@ -80,32 +80,32 @@ export default function NotificationsSettings() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Email Customization */}
|
{/* Channel Configuration */}
|
||||||
<Card className="hover:shadow-md transition-shadow">
|
<Card className="hover:shadow-md transition-shadow">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-2 bg-green-500/10 rounded-lg">
|
<div className="p-2 bg-green-500/10 rounded-lg">
|
||||||
<Palette className="h-6 w-6 text-green-500" />
|
<Settings className="h-6 w-6 text-green-500" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>{__('Email Customization')}</CardTitle>
|
<CardTitle>{__('Channel Configuration')}</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
{__('Customize email appearance and branding')}
|
{__('Configure notification channels and settings')}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{__('Set your brand colors, logo, and email styling. Customize header, footer, and button colors for all email templates.')}
|
{__('Configure email, push notifications, WhatsApp, Telegram, and other notification channels. Set templates and connection settings.')}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center justify-between pt-2">
|
<div className="flex items-center justify-between pt-2">
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
{__('Colors, Logo, Styling')}
|
{__('Email, Push, WhatsApp, Telegram')}
|
||||||
</div>
|
</div>
|
||||||
<Link to="/settings/notifications/email-customization">
|
<Link to="/settings/notifications/channels">
|
||||||
<Button variant="outline" size="sm">
|
<Button variant="outline" size="sm">
|
||||||
{__('Customize')}
|
{__('Configure')}
|
||||||
<ChevronRight className="ml-2 h-4 w-4" />
|
<ChevronRight className="ml-2 h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { SettingsLayout } from '../components/SettingsLayout';
|
||||||
|
import { SettingsCard } from '../components/SettingsCard';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { ChevronLeft, Mail, Bell, MessageCircle, Send, Settings, ChevronRight } from 'lucide-react';
|
||||||
|
import { __ } from '@/lib/i18n';
|
||||||
|
|
||||||
|
interface Channel {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
type: 'builtin' | 'addon';
|
||||||
|
enabled: boolean;
|
||||||
|
configPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ChannelConfiguration() {
|
||||||
|
const channels: Channel[] = [
|
||||||
|
{
|
||||||
|
id: 'email',
|
||||||
|
name: __('Email'),
|
||||||
|
description: __('Email notifications powered by WordPress. Configure templates and SMTP settings.'),
|
||||||
|
icon: <Mail className="h-6 w-6" />,
|
||||||
|
type: 'builtin',
|
||||||
|
enabled: true,
|
||||||
|
configPath: '/settings/notifications/channels/email',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'push',
|
||||||
|
name: __('Push Notifications'),
|
||||||
|
description: __('Browser push notifications for real-time updates. Perfect for PWA.'),
|
||||||
|
icon: <Bell className="h-6 w-6" />,
|
||||||
|
type: 'builtin',
|
||||||
|
enabled: true,
|
||||||
|
configPath: '/settings/notifications/channels/push',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'whatsapp',
|
||||||
|
name: __('WhatsApp'),
|
||||||
|
description: __('Send notifications via WhatsApp Business API. Requires addon installation.'),
|
||||||
|
icon: <MessageCircle className="h-6 w-6" />,
|
||||||
|
type: 'addon',
|
||||||
|
enabled: false,
|
||||||
|
configPath: '/settings/notifications/channels/whatsapp',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'telegram',
|
||||||
|
name: __('Telegram'),
|
||||||
|
description: __('Send notifications via Telegram Bot API. Requires addon installation.'),
|
||||||
|
icon: <Send className="h-6 w-6" />,
|
||||||
|
type: 'addon',
|
||||||
|
enabled: false,
|
||||||
|
configPath: '/settings/notifications/channels/telegram',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const builtinChannels = channels.filter(c => c.type === 'builtin');
|
||||||
|
const addonChannels = channels.filter(c => c.type === 'addon');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsLayout
|
||||||
|
title={__('Channel Configuration')}
|
||||||
|
description={__('Configure global settings for each notification channel')}
|
||||||
|
action={
|
||||||
|
<Link to="/settings/notifications">
|
||||||
|
<Button variant="ghost" size="sm">
|
||||||
|
<ChevronLeft className="mr-2 h-4 w-4" />
|
||||||
|
{__('Back to Notifications')}
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="space-y-6">
|
||||||
|
{/* Info Card */}
|
||||||
|
<SettingsCard
|
||||||
|
title={__('About Channel Configuration')}
|
||||||
|
description={__('Global settings that apply to all notifications')}
|
||||||
|
>
|
||||||
|
<div className="text-sm space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
{__(
|
||||||
|
'Each notification channel has its own configuration for templates and connection settings. These settings apply globally to both staff and customer notifications.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<div className="bg-muted/50 rounded-lg p-4">
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
💡 {__('Tip: Configure your channels here, then enable them for specific events in Staff or Customer Notifications.')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
|
|
||||||
|
{/* Built-in Channels */}
|
||||||
|
<SettingsCard
|
||||||
|
title={__('Built-in Channels')}
|
||||||
|
description={__('Always available notification channels')}
|
||||||
|
>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{builtinChannels.map((channel) => (
|
||||||
|
<div
|
||||||
|
key={channel.id}
|
||||||
|
className="flex items-center justify-between p-4 rounded-lg border bg-card hover:bg-accent/50 transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="p-3 rounded-lg bg-primary/10 text-primary">
|
||||||
|
{channel.icon}
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<h3 className="font-semibold text-base">{channel.name}</h3>
|
||||||
|
<Badge variant="secondary" className="text-xs">
|
||||||
|
{__('Built-in')}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground">{channel.description}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Link to={channel.configPath}>
|
||||||
|
<Button variant="outline" size="sm" className="gap-2">
|
||||||
|
<Settings className="h-4 w-4" />
|
||||||
|
{__('Configure')}
|
||||||
|
<ChevronRight className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
|
|
||||||
|
{/* Addon Channels */}
|
||||||
|
<SettingsCard
|
||||||
|
title={__('Addon Channels')}
|
||||||
|
description={__('Install addons to enable additional notification channels')}
|
||||||
|
>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{addonChannels.map((channel) => (
|
||||||
|
<div
|
||||||
|
key={channel.id}
|
||||||
|
className="flex items-center justify-between p-4 rounded-lg border bg-card opacity-60"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="p-3 rounded-lg bg-muted text-muted-foreground">
|
||||||
|
{channel.icon}
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<h3 className="font-semibold text-base">{channel.name}</h3>
|
||||||
|
<Badge variant="outline" className="text-xs">
|
||||||
|
{__('Addon Required')}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground">{channel.description}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm" disabled>
|
||||||
|
{__('Install Addon')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
|
</div>
|
||||||
|
</SettingsLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { api } from '@/lib/api';
|
import { api } from '@/lib/api';
|
||||||
import { SettingsCard } from '../../components/SettingsCard';
|
import { SettingsCard } from '../../components/SettingsCard';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
import { RefreshCw, Mail, Bell, MessageSquare, Info, MessageCircle, Send, ExternalLink } from 'lucide-react';
|
import { RefreshCw, Mail, Bell, MessageSquare, Info, MessageCircle, Send, ExternalLink, ArrowRight } from 'lucide-react';
|
||||||
import { __ } from '@/lib/i18n';
|
import { __ } from '@/lib/i18n';
|
||||||
|
|
||||||
interface NotificationChannel {
|
interface NotificationChannel {
|
||||||
@@ -58,6 +59,23 @@ export default function CustomerChannels() {
|
|||||||
|
|
||||||
<SettingsCard
|
<SettingsCard
|
||||||
title={__('Channels')}
|
title={__('Channels')}
|
||||||
|
description={__('Enable or disable notification channels for customers')}
|
||||||
|
>
|
||||||
|
<div className="bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg p-4 mb-4">
|
||||||
|
<p className="text-sm text-muted-foreground mb-2">
|
||||||
|
💡 {__('Need to configure channel settings?')}
|
||||||
|
</p>
|
||||||
|
<Link to="/settings/notifications/channels">
|
||||||
|
<Button variant="outline" size="sm" className="gap-2">
|
||||||
|
{__('Go to Channel Configuration')}
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
|
|
||||||
|
<SettingsCard
|
||||||
|
title={__('Available Channels')}
|
||||||
description={__('Manage notification delivery channels')}
|
description={__('Manage notification delivery channels')}
|
||||||
>
|
>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { SettingsLayout } from '../components/SettingsLayout';
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { ChevronLeft } from 'lucide-react';
|
||||||
|
import { __ } from '@/lib/i18n';
|
||||||
|
import EmailCustomization from './EmailCustomization';
|
||||||
|
|
||||||
|
export default function EmailConfiguration() {
|
||||||
|
return (
|
||||||
|
<SettingsLayout
|
||||||
|
title={__('Email Configuration')}
|
||||||
|
description={__('Configure email templates and connection settings')}
|
||||||
|
action={
|
||||||
|
<Link to="/settings/notifications/channels">
|
||||||
|
<Button variant="ghost" size="sm">
|
||||||
|
<ChevronLeft className="mr-2 h-4 w-4" />
|
||||||
|
{__('Back to Channels')}
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Tabs defaultValue="template" className="space-y-6">
|
||||||
|
<TabsList className="grid w-full grid-cols-2">
|
||||||
|
<TabsTrigger value="template">{__('Template Settings')}</TabsTrigger>
|
||||||
|
<TabsTrigger value="connection">{__('Connection Settings')}</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="template" className="space-y-4">
|
||||||
|
<EmailCustomization />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="connection" className="space-y-4">
|
||||||
|
{/* Connection Settings - SMTP Override */}
|
||||||
|
<div className="rounded-lg border bg-card p-6">
|
||||||
|
<h3 className="text-lg font-semibold mb-2">{__('Email Delivery')}</h3>
|
||||||
|
<p className="text-sm text-muted-foreground mb-4">
|
||||||
|
{__(
|
||||||
|
'By default, emails are sent using WordPress wp_mail() function. You can override this with custom SMTP settings if needed.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<div className="bg-muted/50 rounded-lg p-4">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
💡 {__('Tip: For custom SMTP configuration, install a dedicated SMTP plugin like WP Mail SMTP or Easy WP SMTP.')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</SettingsLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { SettingsLayout } from '../components/SettingsLayout';
|
||||||
|
import { SettingsCard } from '../components/SettingsCard';
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { ChevronLeft } from 'lucide-react';
|
||||||
|
import { __ } from '@/lib/i18n';
|
||||||
|
|
||||||
|
export default function PushConfiguration() {
|
||||||
|
return (
|
||||||
|
<SettingsLayout
|
||||||
|
title={__('Push Notifications Configuration')}
|
||||||
|
description={__('Configure push notification templates and connection settings')}
|
||||||
|
action={
|
||||||
|
<Link to="/settings/notifications/channels">
|
||||||
|
<Button variant="ghost" size="sm">
|
||||||
|
<ChevronLeft className="mr-2 h-4 w-4" />
|
||||||
|
{__('Back to Channels')}
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Tabs defaultValue="template" className="space-y-6">
|
||||||
|
<TabsList className="grid w-full grid-cols-2">
|
||||||
|
<TabsTrigger value="template">{__('Template Settings')}</TabsTrigger>
|
||||||
|
<TabsTrigger value="connection">{__('Connection Settings')}</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="template" className="space-y-4">
|
||||||
|
<SettingsCard
|
||||||
|
title={__('Push Notification Template')}
|
||||||
|
description={__('Customize how push notifications appear')}
|
||||||
|
>
|
||||||
|
<div className="space-y-6">
|
||||||
|
{/* Icon */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="push-icon">{__('Notification Icon URL')}</Label>
|
||||||
|
<Input
|
||||||
|
id="push-icon"
|
||||||
|
type="url"
|
||||||
|
placeholder="https://example.com/icon.png"
|
||||||
|
/>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{__('Icon displayed in push notifications (recommended: 192x192px PNG)')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Badge */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="push-badge">{__('Badge Icon URL')}</Label>
|
||||||
|
<Input
|
||||||
|
id="push-badge"
|
||||||
|
type="url"
|
||||||
|
placeholder="https://example.com/badge.png"
|
||||||
|
/>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{__('Small icon shown on notification badge (recommended: 96x96px PNG)')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sound */}
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label>{__('Enable Sound')}</Label>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{__('Play default notification sound')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch defaultChecked />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Vibrate */}
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<Label>{__('Enable Vibration')}</Label>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{__('Vibrate device on notification (mobile only)')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch defaultChecked />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="connection" className="space-y-4">
|
||||||
|
<SettingsCard
|
||||||
|
title={__('Push Notification Service')}
|
||||||
|
description={__('Configure how push notifications are delivered')}
|
||||||
|
>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
|
||||||
|
<h4 className="font-medium text-sm mb-2">{__('Browser-Native Push (Default)')}</h4>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{__(
|
||||||
|
'Uses the browser\'s built-in Push API. No external service required. Works great for PWA applications.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-muted/50 rounded-lg p-4">
|
||||||
|
<p className="text-sm text-muted-foreground mb-3">
|
||||||
|
💡 {__('Want more features? Install one of these addons:')}
|
||||||
|
</p>
|
||||||
|
<ul className="space-y-2 text-sm text-muted-foreground">
|
||||||
|
<li className="flex items-start gap-2">
|
||||||
|
<span className="text-primary">•</span>
|
||||||
|
<span>
|
||||||
|
<strong>{__('Firebase Cloud Messaging (FCM)')}</strong> - {__('Advanced features, analytics, and cross-platform support')}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-start gap-2">
|
||||||
|
<span className="text-primary">•</span>
|
||||||
|
<span>
|
||||||
|
<strong>{__('OneSignal')}</strong> - {__('Easy setup, segmentation, and A/B testing')}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SettingsCard>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</SettingsLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import { api } from '@/lib/api';
|
import { api } from '@/lib/api';
|
||||||
import { SettingsCard } from '../../components/SettingsCard';
|
import { SettingsCard } from '../../components/SettingsCard';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
import { RefreshCw, Mail, MessageCircle, Send, Bell, ExternalLink, Settings, Check, X } from 'lucide-react';
|
import { RefreshCw, Mail, MessageCircle, Send, Bell, ExternalLink, Check, X, ArrowRight } from 'lucide-react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { __ } from '@/lib/i18n';
|
import { __ } from '@/lib/i18n';
|
||||||
import ChannelConfig from '../ChannelConfig';
|
|
||||||
|
|
||||||
interface NotificationChannel {
|
interface NotificationChannel {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -35,8 +35,6 @@ export default function NotificationChannels() {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [pushSubscribed, setPushSubscribed] = useState(false);
|
const [pushSubscribed, setPushSubscribed] = useState(false);
|
||||||
const [pushSupported, setPushSupported] = useState(false);
|
const [pushSupported, setPushSupported] = useState(false);
|
||||||
const [configOpen, setConfigOpen] = useState(false);
|
|
||||||
const [selectedChannel, setSelectedChannel] = useState<NotificationChannel | null>(null);
|
|
||||||
|
|
||||||
// Fetch channels
|
// Fetch channels
|
||||||
const { data: channels, isLoading } = useQuery({
|
const { data: channels, isLoading } = useQuery({
|
||||||
@@ -185,9 +183,20 @@ export default function NotificationChannels() {
|
|||||||
<div className="text-sm space-y-3">
|
<div className="text-sm space-y-3">
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
{__(
|
{__(
|
||||||
'Channels are the different ways notifications can be sent. Email is built-in and always available. Install addons to enable additional channels like WhatsApp, Telegram, SMS, and more.'
|
'Enable or disable notification channels for staff notifications. Toggle channels on/off to control which delivery methods are available.'
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
<div className="bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
|
||||||
|
<p className="text-sm text-muted-foreground mb-2">
|
||||||
|
💡 {__('Need to configure channel settings?')}
|
||||||
|
</p>
|
||||||
|
<Link to="/settings/notifications/channels">
|
||||||
|
<Button variant="outline" size="sm" className="gap-2">
|
||||||
|
{__('Go to Channel Configuration')}
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SettingsCard>
|
</SettingsCard>
|
||||||
|
|
||||||
@@ -234,19 +243,6 @@ export default function NotificationChannels() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedChannel(channel);
|
|
||||||
setConfigOpen(true);
|
|
||||||
}}
|
|
||||||
className="w-full sm:w-auto"
|
|
||||||
>
|
|
||||||
<Settings className="h-4 w-4 sm:mr-2" />
|
|
||||||
<span className="sm:inline">{__('Configure')}</span>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{channel.id === 'push' && !pushSupported && (
|
{channel.id === 'push' && !pushSupported && (
|
||||||
<Badge variant="destructive" className="text-xs w-full sm:w-auto justify-center">
|
<Badge variant="destructive" className="text-xs w-full sm:w-auto justify-center">
|
||||||
{__('Not Supported')}
|
{__('Not Supported')}
|
||||||
@@ -348,19 +344,6 @@ export default function NotificationChannels() {
|
|||||||
</div>
|
</div>
|
||||||
</SettingsCard>
|
</SettingsCard>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Channel Configuration Dialog */}
|
|
||||||
{selectedChannel && (
|
|
||||||
<ChannelConfig
|
|
||||||
open={configOpen}
|
|
||||||
onClose={() => {
|
|
||||||
setConfigOpen(false);
|
|
||||||
setSelectedChannel(null);
|
|
||||||
}}
|
|
||||||
channelId={selectedChannel.id}
|
|
||||||
channelLabel={selectedChannel.label}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user