# EduSight Notification Widget

A modern, accessible React notification center widget built with clean architecture principles, featuring real-time updates, comprehensive notification management, and SDK dependency injection.

## Version 1.0.35 Features

- **Refactored Architecture** - Clean architecture with dependency injection and separation of concerns
- **SDK Integration** - Direct integration with @edusight/notification-sdk using dependency injection pattern
- **Performance Optimized** - Code splitting, memoization, and optimized bundle size (<25KB gzipped)
- **Enhanced Accessibility** - WCAG 2.1 AA compliance with improved keyboard navigation
- **Dynamic Theming** - Runtime theme switching with dark mode support
- **Responsive Design** - Mobile-first approach with responsive breakpoints
- **Error Boundaries** - Comprehensive error handling with fallback components
- **Real-time Sync** - WebSocket integration with fallback polling and cross-tab synchronization
- **Comprehensive Testing** - Unit, integration, and accessibility tests with >90% coverage

## Features

- **Real-time Updates** - WebSocket integration with automatic reconnection and fallback polling
- **Responsive Design** - Works seamlessly on desktop, tablet, and mobile
- **Full CRUD Operations** - Mark as read/unread, archive, delete with optimistic updates
- **Customizable UI** - Dynamic theme support with CSS variables
- **SDK Integration** - Direct integration with @edusight/notification-sdk using dependency injection
- **Accessibility** - Full WCAG 2.1 compliance with keyboard navigation
- **Performance** - Lazy loading, memoization, and optimized re-renders
- **Multi-tenant** - Built-in tenant and environment scoping
- **Error Boundaries** - Component-level error boundaries with fallback UI
- **Live Preferences** - Real-time preference management with debounced saving
- **Cross-tab Sync** - Synchronization across multiple browser tabs
- **Clean Architecture** - Separation of concerns with dependency injection pattern

## Installation

```bash
npm install @edusight/notification-widget
```

### Peer Dependencies

The widget requires React 18+ as a peer dependency:

```bash
npm install react@^18.2.0 react-dom@^18.2.0
```

### Styles

Import the widget styles in your application:

```tsx
import '@edusight/notification-widget/styles';
// or
import '@edusight/notification-widget/styles.css';
```

### Custom Selectors

Each widget section exposes `mx-widget-*` hooks so host apps can override colors or spacing without touching the bundled CSS:

| Attribute | Target |
| --- | --- |
| `data-mx-widget="root"` | Widget shell/bell container |
| `data-mx-widget="popover"` | Notifications popover root |
| `data-mx-widget="tabs"` | Tab navigation bar |
| `data-mx-widget="item"` | Individual notification item |
| `data-mx-widget="action"` | Primary/secondary action buttons |
| `data-mx-widget="bell"` | Bell button itself |

Use these selectors in your global CSS to align the widget with your design system (for example `.mx-widget-root { background-color: #fff; }`). No need to import the widget CSS if you only rely on the shared CSS variables.

## Quick Start

### Basic Setup with NotificationWidget

The main component that provides a complete notification center experience:

```tsx
import { NotificationWidget } from '@edusight/notification-widget';
import '@edusight/notification-widget/styles';

function App() {
  return (
    <NotificationWidget
      sdkConfig={{
        apiKey: 'your-api-key',
        baseUrl: 'https://api.example.com',
        subscriberId: 'user-123',
        tenantId: 'your-tenant',
        environmentId: 'production',
        environment: 'production',
      }}
      position="right"
      size="medium"
      theme="light"
      onError={(error) => console.error('Widget error:', error)}
    />
  );
}
```

### Development Setup

For development, you can use the playground environment:

```bash
cd playground
npm install
npm run dev
```

The playground provides a complete testing environment with:
- Mock data for offline development
- Real-time WebSocket simulation
- All widget features and configurations
- Debug logging and status monitoring

## Core Concepts

### NotificationWidget

The main widget component that provides a complete notification center with SDK dependency injection:

```tsx
import { NotificationWidget } from '@edusight/notification-widget';

<NotificationWidget
  sdkConfig={{
    apiKey: 'your-api-key',
    baseUrl: 'https://api.example.com',
    subscriberId: 'user-123',
    websocketUrl: 'wss://api.example.com',
    environment: 'production',
  }}
  position="right"
  size="medium"
  theme="light"
  className="custom-widget-class"
  onError={(error) => console.error('Widget error:', error)}
/>
```

**Props:**
- `sdkConfig`: `SDKConfiguration` - SDK configuration for dependency injection
- `position`: `'left' | 'right'` - Popover position relative to bell (default: 'right')
- `size`: `'small' | 'medium' | 'large'` - Widget size (default: 'medium')
- `theme`: `'light' | 'dark'` - Theme mode (default: 'light')
- `className`: `string` - Additional CSS classes
- `onError`: `(error: Error) => void` - Error handler callback

### SDK Configuration

The widget uses dependency injection to integrate with the EduSight Notification SDK:

```typescript
interface SDKConfiguration {
  apiKey: string;                                    // API key for authentication
  baseUrl: string;                                   // Base URL for the notification service
  subscriberId: string;                              // Subscriber ID for the current user
  tenantId: string;                                  // Tenant ID for multi-tenant support
  environmentId: string;                             // Environment ID for environment scoping
  environment: 'development' | 'staging' | 'production'; // Environment setting
}
```

**Note:** WebSocket URL is automatically derived from `baseUrl` by the SDK. The SDK converts HTTP URLs to WebSocket URLs automatically (http → ws, https → wss).

### useSDK Hook

Access the SDK instance from within the widget context:

```tsx
import { useSDK } from '@edusight/notification-widget';

function CustomComponent() {
  const { client, isInitialized, error } = useSDK();
  
  if (!isInitialized) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  // Use the SDK client for custom operations
  const handleCustomAction = async () => {
    await client.notifications.markAsRead('notification-id');
  };
  
  return <button onClick={handleCustomAction}>Custom Action</button>;
}
```

## Components

### NotificationWidget

Main notification center component with complete functionality:

```tsx
import { NotificationWidget } from '@edusight/notification-widget';

<NotificationWidget
  sdkConfig={sdkConfig}
  position="right"
  size="medium"
  theme="light"
  onError={handleError}
/>
```

Features:
- Bell icon with unread count badge
- Popover with notification list
- Real-time WebSocket updates with fallback polling
- Live preferences management
- Error boundaries with fallback UI
- Cross-tab synchronization
- Optimistic updates

### BellComponent

Notification bell icon with unread badge (used internally by NotificationWidget):

```tsx
import { BellComponent } from '@edusight/notification-widget';

<BellComponent
  unreadCount={5}
  onClick={handleClick}
  size="medium"
  disabled={false}
/>
```

### InboxPopover

Notification popover content (used internally by NotificationWidget):

```tsx
import { InboxPopover } from '@edusight/notification-widget';

<InboxPopover
  isOpen={true}
  onClose={handleClose}
  position="right"
  currentView="notifications"
  onViewChange={handleViewChange}
  notifications={notifications}
  onNotificationAction={handleAction}
  preferences={preferences}
  onPreferenceChange={handlePreferenceChange}
/>
```

### NotificationItem

Individual notification item component:

```tsx
import { NotificationItem } from '@edusight/notification-widget';

<NotificationItem
  notification={notification}
  onAction={handleAction}
  isSelected={false}
  onSelect={handleSelect}
/>
```

### PreferencesView

Notification preference management component:

```tsx
import { PreferencesView } from '@edusight/notification-widget';

<PreferencesView
  preferences={preferences}
  onChange={handleChange}
  isLoading={false}
/>
```

### Error Boundaries

The widget includes comprehensive error boundaries:

```tsx
import { 
  NotificationWidgetErrorBoundary,
  ComponentErrorBoundary 
} from '@edusight/notification-widget';

// Main widget error boundary
<NotificationWidgetErrorBoundary onError={handleError}>
  <YourComponent />
</NotificationWidgetErrorBoundary>

// Component-level error boundary
<ComponentErrorBoundary componentName="CustomComponent">
  <CustomComponent />
</ComponentErrorBoundary>
```

## Hooks

### useLivePreferences

Manage notification preferences with real-time saving:

```tsx
import { useLivePreferences } from '@edusight/notification-widget';

const { 
  updatePreference, 
  isSaving, 
  error 
} = useLivePreferences({
  preferences: currentPreferences,
  onPreferencesChange: handleChange,
  onError: handleError,
});

// Update a preference (automatically debounced and saved)
updatePreference('channels.email', true);
```

### useSDK

Access the SDK instance within the widget context:

```tsx
import { useSDK } from '@edusight/notification-widget';

const { client, isInitialized, error } = useSDK();

if (!isInitialized) return <div>Loading...</div>;

// Use SDK methods directly
const markAsRead = async (id: string) => {
  await client.notifications.markAsRead(id);
};
```

### Custom Hooks Integration

The widget is designed to work with custom hooks that use the SDK:

```tsx
// Custom hook using the SDK
function useCustomNotifications() {
  const { client } = useSDK();
  const [notifications, setNotifications] = useState([]);
  
  useEffect(() => {
    if (client) {
      client.notifications.list().then(setNotifications);
    }
  }, [client]);
  
  return notifications;
}
```

## Configuration

### SDKConfiguration

```typescript
interface SDKConfiguration {
  apiKey: string;                                    // API key for authentication
  baseUrl: string;                                   // Base URL for the notification service
  subscriberId: string;                              // Subscriber ID for the current user
  tenantId: string;                                  // Tenant ID for multi-tenant support
  environmentId: string;                             // Environment ID for environment scoping
  environment: 'development' | 'staging' | 'production'; // Environment setting
}
```

### NotificationWidgetProps

```typescript
interface NotificationWidgetProps {
  sdkConfig: SDKConfiguration;                       // SDK configuration for dependency injection
  position?: 'left' | 'right';                      // Popover position (default: 'right')
  size?: 'small' | 'medium' | 'large';              // Widget size (default: 'medium')
  theme?: 'light' | 'dark';                         // Theme mode (default: 'light')
  className?: string;                                // Additional CSS classes
  onError?: (error: Error) => void;                 // Error handler callback
}
```

### Widget State Management

The widget uses a reducer pattern for state management:

```typescript
interface WidgetState {
  notifications: Notification[];                    // Current notifications
  unreadCount: number;                              // Unread notification count
  preferences: NotificationPreferences;            // User preferences
  ui: {
    isOpen: boolean;                                // Popover open state
    currentView: 'notifications' | 'preferences';  // Current view
    selectedNotifications: string[];               // Selected notification IDs
    isLoading: boolean;                            // Loading state
    error: Error | null;                           // Error state
  };
  websocket: {
    connected: boolean;                            // WebSocket connection status
    reconnecting: boolean;                         // Reconnection state
  };
}
```

## Styling & Theming

### Tailwind CSS Integration

The widget is built with Tailwind CSS and follows clean design principles. All components use Tailwind utility classes for consistent styling.

### Theme Support

The widget supports light and dark themes:

```tsx
// Light theme (default)
<NotificationWidget theme="light" sdkConfig={config} />

// Dark theme
<NotificationWidget theme="dark" sdkConfig={config} />
```

### Custom Styling

Override widget styles using CSS classes:

```tsx
<NotificationWidget 
  className="custom-notification-widget" 
  sdkConfig={config} 
/>
```

```css
.custom-notification-widget {
  /* Custom styles for the widget container */
}

.custom-notification-widget .notification-bell {
  /* Custom styles for the bell component */
}

.custom-notification-widget .notification-popover {
  /* Custom styles for the popover */
}
```

### CSS Variables

The widget uses CSS variables for theming:

```css
:root {
  --notification-primary: #3b82f6;
  --notification-primary-hover: #2563eb;
  --notification-background: #ffffff;
  --notification-text: #1f2937;
  --notification-border: #e5e7eb;
}

[data-theme='dark'] {
  --notification-primary: #60a5fa;
  --notification-primary-hover: #3b82f6;
  --notification-background: #1f2937;
  --notification-text: #f9fafb;
  --notification-border: #374151;
}
```

## Performance Optimizations

### Architecture Benefits

The refactored architecture provides several performance benefits:

- **Dependency Injection**: SDK is initialized once and reused across components
- **Error Boundaries**: Component-level error isolation prevents cascading failures
- **Optimistic Updates**: UI updates immediately while API calls happen in background
- **Debounced Preferences**: Preference changes are debounced to reduce API calls
- **Fallback Polling**: Automatic fallback to polling when WebSocket fails

### Code Splitting

The widget includes optimized code splitting:

```tsx
// Main widget bundle: ~17KB gzipped
import { NotificationWidget } from '@edusight/notification-widget';

// Components are automatically code-split
// - Bell component: Loaded immediately
// - Popover content: Loaded on first open
// - Preferences view: Loaded when accessed
```

### Memory Management

The widget includes proper cleanup:

- WebSocket connections are properly closed
- Event listeners are removed on unmount
- Timers and intervals are cleared
- Component state is reset on errors

### Bundle Size

Optimized bundle sizes:

- Main widget: ~17KB gzipped
- SDK integration: ~5KB additional
- Styles: ~25KB (includes Tailwind utilities)
- Total: ~47KB gzipped (complete package)

## Accessibility

The widget includes:

- ✅ WCAG 2.1 Level AA compliance
- ✅ Keyboard navigation (Tab, Enter, Escape)
- ✅ ARIA labels and roles
- ✅ Screen reader support
- ✅ High contrast mode support
- ✅ Focus management

Use the `AccessibilityProvider` for custom accessibility options:

```tsx
import { AccessibilityProvider } from '@edusight/notification-widget';

<AccessibilityProvider options={{ highContrast: true }}>
  <YourApp />
</AccessibilityProvider>
```

## Playground Development Environment

A comprehensive development environment is included for testing and debugging:

```bash
cd playground
npm install
npm run dev
```

The playground demonstrates:

- Complete NotificationWidget integration
- SDK dependency injection pattern
- Real-time WebSocket simulation
- All notification operations (CRUD)
- Live preferences management
- Error boundary testing
- Cross-tab synchronization
- Responsive design testing
- Debug logging and monitoring

### Playground Features

- **Configuration Panel**: Test different SDK configurations
- **Debug Console**: Real-time logging and status monitoring
- **Connection Status**: API and WebSocket connection indicators
- **Feature Testing**: All widget features in one place
- **Error Simulation**: Test error boundaries and fallbacks

See the playground README for detailed development documentation.

## Build Status

| Component | Status | Bundle Size | Features |
|-----------|--------|-------------|----------|
| Widget | ✅ Success | ~17 KB (gzipped) | Complete notification center |
| SDK Integration | ✅ Success | ~5 KB (gzipped) | Dependency injection |
| Styles | ✅ Success | ~25 KB (gzipped) | Tailwind utilities |
| Playground | ✅ Success | ~330 KB (gzipped) | Development environment |

## Development

### Build

```bash
npm run build
```

Generates:
- `dist/index.esm.js` - ES modules build
- `dist/index.cjs.js` - CommonJS build
- `dist/index.d.ts` - TypeScript declarations
- `dist/index.css` - Compiled styles

### Test

```bash
npm test              # Run all tests
npm run test:watch    # Watch mode
npm run test:coverage # Coverage report
```

Test coverage: >90% across all components and hooks

### Lint

```bash
npm run lint          # Check for issues
npm run lint:fix      # Fix auto-fixable issues
```

### Type Check

```bash
npm run type-check    # TypeScript type checking
```

## Integration Workflow

1. **Install the widget**: `npm install @edusight/notification-widget`
2. **Import styles**: `import '@edusight/notification-widget/styles'`
3. **Configure SDK**: Set up your SDK configuration object
4. **Add NotificationWidget**: Place the widget component in your app
5. **Handle errors**: Implement error handling for production use
6. **Test with playground**: Use the included playground for development

### Example Integration

```tsx
import React from 'react';
import { NotificationWidget } from '@edusight/notification-widget';
import '@edusight/notification-widget/styles';

function App() {
  const sdkConfig = {
    apiKey: process.env.REACT_APP_NOTIFICATION_API_KEY!,
    baseUrl: process.env.REACT_APP_NOTIFICATION_API_URL!,
    subscriberId: getCurrentUserId(),
    tenantId: getCurrentTenantId(),
    environmentId: getCurrentEnvironmentId(),
    environment: process.env.NODE_ENV as 'development' | 'staging' | 'production',
  };

  const handleError = (error: Error) => {
    console.error('Notification widget error:', error);
    // Send to error tracking service
    errorTracker.captureException(error);
  };

  return (
    <div className="app">
      <header className="app-header">
        <h1>My Application</h1>
        <NotificationWidget
          sdkConfig={sdkConfig}
          position="right"
          size="medium"
          theme="light"
          onError={handleError}
        />
      </header>
      <main>
        {/* Your app content */}
      </main>
    </div>
  );
}

export default App;
```

## Troubleshooting

### "useSDK must be used within a NotificationWidget"

Ensure your component is used within the NotificationWidget context:

```tsx
// ❌ Wrong - useSDK outside widget context
function MyComponent() {
  const { client } = useSDK(); // This will throw an error
  return <div>...</div>;
}

// ✅ Correct - Custom component within widget
<NotificationWidget sdkConfig={config}>
  {/* Custom components can use useSDK here */}
</NotificationWidget>
```

### SDK Configuration Issues

1. **Check required fields**: Ensure all required SDK config fields are provided
2. **Verify URLs**: Check that `baseUrl` and `websocketUrl` are correct
3. **Environment mismatch**: Ensure `environment` matches your deployment
4. **API key validation**: Verify the API key is valid and has proper permissions

### WebSocket Connection Issues

1. **URL format**: Ensure WebSocket URL uses `ws://` or `wss://` protocol
2. **CORS settings**: Check CORS configuration on the backend
3. **Firewall/proxy**: Verify WebSocket connections aren't blocked
4. **Fallback polling**: The widget automatically falls back to polling if WebSocket fails

### Performance Issues

1. **Bundle size**: Check if you're importing the entire widget when you only need parts
2. **Re-renders**: Use React DevTools to identify unnecessary re-renders
3. **Memory leaks**: Ensure proper cleanup of event listeners and timers
4. **Error boundaries**: Check if error boundaries are catching and handling errors properly

### Styling Issues

1. **CSS conflicts**: Ensure your CSS doesn't conflict with widget styles
2. **Tailwind purging**: Make sure Tailwind isn't purging widget classes
3. **Theme application**: Verify theme prop is being applied correctly
4. **Custom classes**: Check that custom className prop is being used

## API Reference

### Exported Components

```typescript
export {
  NotificationWidget,        // Main widget component
  BellComponent,            // Bell icon with badge
  InboxPopover,             // Popover content
  NotificationItem,         // Individual notification
  PreferencesView,          // Preferences management
  NotificationWidgetErrorBoundary, // Main error boundary
  ComponentErrorBoundary,   // Component-level error boundary
};
```

### Exported Hooks

```typescript
export {
  useSDK,                   // Access SDK instance
  useLivePreferences,       // Live preferences management
};
```

### Exported Types

```typescript
export type {
  NotificationWidgetProps,  // Main widget props
  SDKConfiguration,         // SDK config interface
  WidgetState,             // Widget state interface
  WidgetAction,            // State action types
  Notification,            // Core notification type
  NotificationPreferences, // Preferences interface
  WidgetError,             // Error interface
};
```

### Re-exported SDK Types

```typescript
export type {
  Notification as SDKNotification,
  NotificationFilters,
} from '@edusight/notification-sdk';
```

## Architecture

### Clean Architecture Principles

The widget follows clean architecture principles:

1. **Separation of Concerns**: UI, business logic, and data access are separated
2. **Dependency Injection**: SDK is injected rather than directly imported
3. **Error Boundaries**: Component-level error isolation
4. **State Management**: Centralized state with reducer pattern
5. **Event Handling**: Proper event cleanup and memory management

### Component Hierarchy

```
NotificationWidget
├── SDKProvider (Dependency Injection)
├── NotificationWidgetErrorBoundary
└── NotificationWidgetInternal
    ├── ComponentErrorBoundary (BellComponent)
    │   └── BellComponent
    └── ComponentErrorBoundary (InboxPopover)
        └── InboxPopover
            ├── NotificationsList
            │   └── NotificationItem[]
            └── PreferencesView
```

### State Flow

1. **SDK Initialization**: SDKProvider initializes and provides SDK instance
2. **State Management**: useReducer manages widget state centrally
3. **Real-time Updates**: WebSocket events update state via reducer actions
4. **Optimistic Updates**: UI updates immediately, API calls happen async
5. **Error Handling**: Errors are caught by boundaries and handled gracefully

## License

MIT
