// src/components/NotificationToastHandler.tsx /** * Global notification toast handler * Listens for WebSocket notifications and displays them as toasts * Should be rendered once at the app root level */ import { useCallback, useEffect } from 'react'; import { useWebSocket } from '../hooks/useWebSocket'; import { useEventBus } from '../hooks/useEventBus'; import toast from 'react-hot-toast'; import type { DealNotificationData, SystemMessageData } from '../types/websocket'; import { formatCurrency } from '../utils/formatUtils'; interface NotificationToastHandlerProps { /** * Whether to enable toast notifications * @default true */ enabled?: boolean; /** * Whether to play a sound when notifications arrive * @default false */ playSound?: boolean; /** * Custom sound URL (if playSound is true) */ soundUrl?: string; } export function NotificationToastHandler({ enabled = true, playSound = false, soundUrl = '/notification-sound.mp3', }: NotificationToastHandlerProps) { // Connect to WebSocket const { isConnected, error } = useWebSocket({ autoConnect: true, onConnect: () => { if (enabled) { toast.success('Connected to live notifications', { duration: 2000, icon: 'đĸ', }); } }, onDisconnect: () => { if (enabled && error) { toast.error('Disconnected from live notifications', { duration: 3000, icon: 'đ´', }); } }, }); // Play notification sound const playNotificationSound = useCallback(() => { if (!playSound) return; try { const audio = new Audio(soundUrl); audio.volume = 0.3; audio.play().catch((error) => { console.warn('Failed to play notification sound:', error); }); } catch (error) { console.warn('Failed to play notification sound:', error); } }, [playSound, soundUrl]); // Handle deal notifications const handleDealNotification = useCallback( (data?: DealNotificationData) => { if (!enabled || !data) return; playNotificationSound(); const dealsCount = data.deals.length; const firstDeal = data.deals[0]; // Show toast with deal information toast.success(