import React, { useState, useEffect } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { api } from '@/lib/api'; import { SettingsCard } from '../components/SettingsCard'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Switch } from '@/components/ui/switch'; import { RefreshCw, Mail, MessageCircle, Send, Bell, ExternalLink, Settings, Check, X } from 'lucide-react'; import { toast } from 'sonner'; import { __ } from '@/lib/i18n'; import ChannelConfig from './ChannelConfig'; interface NotificationChannel { id: string; label: string; icon: string; enabled: boolean; builtin?: boolean; addon?: string; } // Helper function to convert VAPID key function urlBase64ToUint8Array(base64String: string) { const padding = '='.repeat((4 - (base64String.length % 4)) % 4); const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/'); const rawData = window.atob(base64); const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; } export default function NotificationChannels() { const queryClient = useQueryClient(); const [pushSubscribed, setPushSubscribed] = useState(false); const [pushSupported, setPushSupported] = useState(false); const [configOpen, setConfigOpen] = useState(false); const [selectedChannel, setSelectedChannel] = useState(null); // Fetch channels const { data: channels, isLoading } = useQuery({ queryKey: ['notification-channels'], queryFn: () => api.get('/notifications/channels'), }); // Toggle channel mutation const toggleChannelMutation = useMutation({ mutationFn: async ({ channelId, enabled }: { channelId: string; enabled: boolean }) => { const response = await api.post('/notifications/channels/toggle', { channelId, enabled }); return response; }, onSuccess: (data, variables) => { // Update cache with server response queryClient.setQueryData(['notification-channels'], (old: any) => { if (!old) return old; return old.map((channel: any) => channel.id === variables.channelId ? { ...channel, enabled: data.enabled } : channel ); }); toast.success(__('Channel updated')); }, onError: (error: any) => { // Refetch on error to sync with server queryClient.invalidateQueries({ queryKey: ['notification-channels'] }); toast.error(error?.message || __('Failed to update channel')); }, }); // Check push notification support useEffect(() => { if ('Notification' in window && 'serviceWorker' in navigator && 'PushManager' in window) { setPushSupported(true); // Check if already subscribed checkPushSubscription(); } }, []); const checkPushSubscription = async () => { try { const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.getSubscription(); setPushSubscribed(!!subscription); } catch (error) { console.error('Error checking push subscription:', error); } }; const subscribeToPush = useMutation({ mutationFn: async () => { // Request notification permission const permission = await Notification.requestPermission(); if (permission !== 'granted') { throw new Error('Notification permission denied'); } // Get VAPID public key const { publicKey } = await api.get('/notifications/push/vapid-key'); // Register service worker if not already registered let registration = await navigator.serviceWorker.getRegistration(); if (!registration) { // For now, we'll wait for service worker to be registered elsewhere // In production, you'd register it here registration = await navigator.serviceWorker.ready; } // Subscribe to push const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(publicKey), }); // Send subscription to server await api.post('/notifications/push/subscribe', { subscription: subscription.toJSON(), }); return subscription; }, onSuccess: () => { setPushSubscribed(true); toast.success(__('Push notifications enabled')); }, onError: (error: any) => { console.error('Push subscription error:', error); toast.error(error?.message || __('Failed to enable push notifications')); }, }); const unsubscribeFromPush = useMutation({ mutationFn: async () => { const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.getSubscription(); if (subscription) { await subscription.unsubscribe(); // Notify server await api.post('/notifications/push/unsubscribe', { subscriptionId: btoa(JSON.stringify(subscription.toJSON())), }); } }, onSuccess: () => { setPushSubscribed(false); toast.success(__('Push notifications disabled')); }, onError: (error: any) => { toast.error(error?.message || __('Failed to disable push notifications')); }, }); const getChannelIcon = (channelId: string) => { switch (channelId) { case 'email': return ; case 'whatsapp': return ; case 'telegram': return ; default: return ; } }; if (isLoading) { return (
); } const builtinChannels = channels?.filter((c: NotificationChannel) => c.builtin) || []; const addonChannels = channels?.filter((c: NotificationChannel) => !c.builtin) || []; return (
{/* Info Card */}

{__( '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.' )}

{/* All Channels */}
{builtinChannels.map((channel: NotificationChannel) => (
{getChannelIcon(channel.id)}

{channel.label}

{__('Built-in')}

{channel.id === 'email' && __('Email notifications powered by WooCommerce. Configure templates and SMTP settings.')} {channel.id === 'push' && __('Browser push notifications for real-time updates. Perfect for PWA.')}

{/* Channel Enable/Disable Toggle */}
{channel.enabled ? __('Enabled') : __('Disabled')} { toggleChannelMutation.mutate({ channelId: channel.id, enabled: checked }); // If enabling push, also subscribe if (channel.id === 'push' && checked && pushSupported && !pushSubscribed) { subscribeToPush.mutate(); } }} disabled={toggleChannelMutation.isPending} />
{channel.id === 'push' && !pushSupported && ( {__('Not Supported')} )}
))}
{/* Addon Channels */} {addonChannels.length > 0 ? (
{addonChannels.map((channel: NotificationChannel) => (
{getChannelIcon(channel.id)}

{channel.label}

{__('Addon')} {channel.enabled ? __('Active') : __('Inactive')}

{__('Provided by')} {channel.addon}

))}
) : (

{__( 'Install notification addons to send notifications via WhatsApp, Telegram, SMS, and more.' )}

{/* Example addon cards */}

{__('WhatsApp Notifications')}

{__('Send order updates and notifications via WhatsApp Business API')}

{__('Telegram Notifications')}

{__('Get instant notifications in your Telegram channel or group')}

{__('SMS Notifications')}

{__('Send SMS notifications via Twilio, Nexmo, or other providers')}

)} {/* Channel Configuration Dialog */} {selectedChannel && ( { setConfigOpen(false); setSelectedChannel(null); }} channelId={selectedChannel.id} channelLabel={selectedChannel.label} /> )}
); }