# WebSocket Real-Time Notifications - Usage Guide

This guide shows you how to use the WebSocket real-time notification system in your React components.

## Quick Start

### 1. Enable Global Notifications

Add the `NotificationToastHandler` to your root `App.tsx`:

```tsx
// src/App.tsx
import { Toaster } from 'react-hot-toast';
import { NotificationToastHandler } from './components/NotificationToastHandler';

function App() {
  return (
    <>
      {/* React Hot Toast container */}
      <Toaster position="top-right" />

      {/* WebSocket notification handler (renders nothing, handles side effects) */}
      <NotificationToastHandler
        enabled={true}
        playSound={false} // Set to true to play notification sounds
      />

      {/* Your app routes and components */}
      <YourAppContent />
    </>
  );
}
```

### 2. Add Notification Bell to Header

```tsx
// src/components/Header.tsx
import { NotificationBell } from './components/NotificationBell';
import { useNavigate } from 'react-router-dom';

function Header() {
  const navigate = useNavigate();

  return (
    <header className="flex items-center justify-between p-4">
      <h1>Flyer Crawler</h1>

      <div className="flex items-center gap-4">
        {/* Notification bell with unread count */}
        <NotificationBell onClick={() => navigate('/notifications')} showConnectionStatus={true} />

        <UserMenu />
      </div>
    </header>
  );
}
```

### 3. Listen for Notifications in Components

```tsx
// src/pages/DealsPage.tsx
import { useEventBus } from '../hooks/useEventBus';
import { useCallback, useState } from 'react';
import type { DealNotificationData } from '../types/websocket';

function DealsPage() {
  const [deals, setDeals] = useState([]);

  // Listen for new deal notifications
  const handleDealNotification = useCallback((data: DealNotificationData) => {
    console.log('New deals received:', data.deals);

    // Update your deals list
    setDeals((prev) => [...data.deals, ...prev]);

    // Or refetch from API
    // refetchDeals();
  }, []);

  useEventBus('notification:deal', handleDealNotification);

  return (
    <div>
      <h1>Deals</h1>
      {/* Render deals */}
    </div>
  );
}
```

## Available Components

### `NotificationBell`

A notification bell icon with unread count and connection status indicator.

**Props:**

- `onClick?: () => void` - Callback when bell is clicked
- `showConnectionStatus?: boolean` - Show green/red/yellow connection dot (default: `true`)
- `className?: string` - Custom CSS classes

**Example:**

```tsx
<NotificationBell
  onClick={() => navigate('/notifications')}
  showConnectionStatus={true}
  className="mr-4"
/>
```

### `ConnectionStatus`

A simple status indicator showing if WebSocket is connected (no bell icon).

**Example:**

```tsx
<ConnectionStatus />
```

### `NotificationToastHandler`

Global handler that listens for WebSocket events and displays toasts. Should be rendered once at app root.

**Props:**

- `enabled?: boolean` - Enable/disable toast notifications (default: `true`)
- `playSound?: boolean` - Play sound on notifications (default: `false`)
- `soundUrl?: string` - Custom notification sound URL

**Example:**

```tsx
<NotificationToastHandler enabled={true} playSound={true} soundUrl="/custom-sound.mp3" />
```

## Available Hooks

### `useWebSocket`

Connect to the WebSocket server and manage connection state.

**Options:**

- `autoConnect?: boolean` - Auto-connect on mount (default: `true`)
- `maxReconnectAttempts?: number` - Max reconnect attempts (default: `5`)
- `reconnectDelay?: number` - Base reconnect delay in ms (default: `1000`)
- `onConnect?: () => void` - Callback on connection
- `onDisconnect?: () => void` - Callback on disconnect
- `onError?: (error: Event) => void` - Callback on error

**Returns:**

- `isConnected: boolean` - Connection status
- `isConnecting: boolean` - Connecting state
- `error: string | null` - Error message if any
- `connect: () => void` - Manual connect function
- `disconnect: () => void` - Manual disconnect function
- `send: (message: WebSocketMessage) => void` - Send message to server

**Example:**

```tsx
const { isConnected, error, connect, disconnect } = useWebSocket({
  autoConnect: true,
  maxReconnectAttempts: 3,
  onConnect: () => console.log('Connected!'),
  onDisconnect: () => console.log('Disconnected!'),
});

return (
  <div>
    <p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
    {error && <p>Error: {error}</p>}
    <button onClick={connect}>Reconnect</button>
  </div>
);
```

### `useEventBus`

Subscribe to event bus events (used with WebSocket integration).

**Parameters:**

- `event: string` - Event name to listen for
- `callback: (data?: T) => void` - Callback function

**Available Events:**

- `'notification:deal'` - Deal notifications (`DealNotificationData`)
- `'notification:system'` - System messages (`SystemMessageData`)
- `'notification:error'` - Error messages (`{ message: string; code?: string }`)

**Example:**

```tsx
import { useEventBus } from '../hooks/useEventBus';
import type { DealNotificationData } from '../types/websocket';

function MyComponent() {
  useEventBus<DealNotificationData>('notification:deal', (data) => {
    console.log('Received deal:', data);
  });

  return <div>Listening for deals...</div>;
}
```

## Message Types

### Deal Notification

```typescript
interface DealNotificationData {
  notification_id?: string;
  deals: Array<{
    item_name: string;
    best_price_in_cents: number;
    store_name: string;
    store_id: string;
  }>;
  user_id: string;
  message: string;
}
```

### System Message

```typescript
interface SystemMessageData {
  message: string;
  severity: 'info' | 'warning' | 'error';
}
```

## Advanced Usage

### Custom Notification Handling

If you don't want to use the default `NotificationToastHandler`, you can create your own:

```tsx
import { useWebSocket } from '../hooks/useWebSocket';
import { useEventBus } from '../hooks/useEventBus';
import type { DealNotificationData } from '../types/websocket';

function CustomNotificationHandler() {
  const { isConnected } = useWebSocket({ autoConnect: true });

  useEventBus<DealNotificationData>('notification:deal', (data) => {
    // Custom handling - e.g., update Redux store
    dispatch(addDeals(data.deals));

    // Show custom UI
    showCustomNotification(data.message);
  });

  return null; // Or return your custom UI
}
```

### Conditional WebSocket Connection

```tsx
import { useWebSocket } from '../hooks/useWebSocket';
import { useAuth } from '../hooks/useAuth';

function ConditionalWebSocket() {
  const { user } = useAuth();

  // Only connect if user is logged in
  useWebSocket({
    autoConnect: !!user,
  });

  return null;
}
```

### Send Messages to Server

```tsx
import { useWebSocket } from '../hooks/useWebSocket';

function PingComponent() {
  const { send, isConnected } = useWebSocket();

  const sendPing = () => {
    send({
      type: 'ping',
      data: {},
      timestamp: new Date().toISOString(),
    });
  };

  return (
    <button onClick={sendPing} disabled={!isConnected}>
      Send Ping
    </button>
  );
}
```

## Admin Monitoring

### Get WebSocket Stats

Admin users can check WebSocket connection statistics:

```bash
# Get connection stats
curl -H "Authorization: Bearer <admin-token>" \
  http://localhost:3001/api/admin/websocket/stats
```

**Response:**

```json
{
  "success": true,
  "data": {
    "totalUsers": 42,
    "totalConnections": 67
  }
}
```

### Admin Dashboard Integration

```tsx
import { useEffect, useState } from 'react';

function AdminWebSocketStats() {
  const [stats, setStats] = useState({ totalUsers: 0, totalConnections: 0 });

  useEffect(() => {
    const fetchStats = async () => {
      const response = await fetch('/api/admin/websocket/stats', {
        headers: { Authorization: `Bearer ${token}` },
      });
      const data = await response.json();
      setStats(data.data);
    };

    fetchStats();
    const interval = setInterval(fetchStats, 5000); // Poll every 5s

    return () => clearInterval(interval);
  }, []);

  return (
    <div className="p-4 border rounded">
      <h3>WebSocket Stats</h3>
      <p>Connected Users: {stats.totalUsers}</p>
      <p>Total Connections: {stats.totalConnections}</p>
    </div>
  );
}
```

## Troubleshooting

### Connection Issues

1. **Check JWT Token**: WebSocket requires a valid JWT token in cookies or query string
2. **Check Server Logs**: Look for WebSocket connection errors in server logs
3. **Check Browser Console**: WebSocket errors are logged to console
4. **Verify Path**: WebSocket server is at `ws://localhost:3001/ws` (or `wss://` for HTTPS)

### Not Receiving Notifications

1. **Check Connection Status**: Use `<ConnectionStatus />` to verify connection
2. **Verify Event Name**: Ensure you're listening to the correct event (`notification:deal`, etc.)
3. **Check User ID**: Notifications are sent to specific users - verify JWT user_id matches

### High Memory Usage

1. **Connection Leaks**: Ensure components using `useWebSocket` are properly unmounting
2. **Event Listeners**: `useEventBus` automatically cleans up, but verify no manual listeners remain
3. **Check Stats**: Use `/api/admin/websocket/stats` to monitor connection count

## Testing

### Unit Tests

```typescript
import { renderHook } from '@testing-library/react';
import { useWebSocket } from '../hooks/useWebSocket';

describe('useWebSocket', () => {
  it('should connect automatically', () => {
    const { result } = renderHook(() => useWebSocket({ autoConnect: true }));
    expect(result.current.isConnecting).toBe(true);
  });
});
```

### Integration Tests

See [src/tests/integration/websocket.integration.test.ts](../src/tests/integration/websocket.integration.test.ts) for comprehensive integration tests.

## Related Documentation

- [ADR-022: Real-time Notification System](./adr/0022-real-time-notification-system.md)
- [ADR-036: Event Bus and Pub/Sub Pattern](./adr/0036-event-bus-and-pub-sub-pattern.md)
- [ADR-042: Email and Notification Architecture](./adr/0042-email-and-notification-architecture.md)
