# Push Notifications Client-Side Setup Guide

This guide will help you set up push notifications on the client side to fix the `Cannot read properties of undefined (reading 'pushManager')` error.

## Prerequisites

1. Firebase project with FCM enabled
2. Service worker file
3. Firebase configuration object

## Step 1: Firebase Configuration

Create a `firebase-config.js` file in your client-side project:

```javascript
// firebase-config.js
import { initializeApp } from 'firebase/app';
import { getMessaging, getToken, onMessage } from 'firebase/messaging';

const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "c4i-dev-test-1.firebaseapp.com",
  projectId: "c4i-dev-test-1",
  storageBucket: "c4i-dev-test-1.appspot.com",
  messagingSenderId: "your-sender-id",
  appId: "your-app-id"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);

// Initialize Firebase Cloud Messaging and get a reference to the service
const messaging = getMessaging(app);

export { messaging, getToken, onMessage };
```

## Step 2: Service Worker

Create a `firebase-messaging-sw.js` file in your public directory:

```javascript
// firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/9.0.0/firebase-messaging-compat.js');

const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "c4i-dev-test-1.firebaseapp.com",
  projectId: "c4i-dev-test-1",
  storageBucket: "c4i-dev-test-1.appspot.com",
  messagingSenderId: "your-sender-id",
  appId: "your-app-id"
};

firebase.initializeApp(firebaseConfig);

const messaging = firebase.messaging();

// Handle background messages
messaging.onBackgroundMessage((payload) => {
  console.log('Received background message ', payload);
  
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: '/icon-192x192.png', // Add your icon
    badge: '/badge-72x72.png', // Add your badge
    data: payload.data
  };

  self.registration.showNotification(notificationTitle, notificationOptions);
});
```

## Step 3: Push Notification Manager

Create a `push-notification-manager.js` file:

```javascript
// push-notification-manager.js
import { messaging, getToken, onMessage } from './firebase-config.js';

class PushNotificationManager {
  constructor() {
    this.isSupported = 'serviceWorker' in navigator && 'PushManager' in window;
    this.registration = null;
    this.messaging = messaging;
  }

  async initialize() {
    if (!this.isSupported) {
      console.warn('Push notifications are not supported in this browser');
      return false;
    }

    try {
      // Register service worker
      this.registration = await this.registerServiceWorker();
      
      if (!this.registration) {
        throw new Error('Service worker registration failed');
      }

      // Request notification permission
      const permission = await this.requestPermission();
      if (permission !== 'granted') {
        throw new Error('Notification permission denied');
      }

      // Get FCM token
      const token = await this.getFCMToken();
      if (token) {
        console.log('FCM Token:', token);
        return token;
      }

      return null;
    } catch (error) {
      console.error('Error initializing push notifications:', error);
      return null;
    }
  }

  async registerServiceWorker() {
    try {
      const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
      console.log('Service Worker registered successfully:', registration);
      return registration;
    } catch (error) {
      console.error('Service Worker registration failed:', error);
      return null;
    }
  }

  async requestPermission() {
    try {
      const permission = await Notification.requestPermission();
      console.log('Notification permission:', permission);
      return permission;
    } catch (error) {
      console.error('Error requesting notification permission:', error);
      return 'denied';
    }
  }

  async getFCMToken() {
    try {
      // Wait for service worker to be ready
      await navigator.serviceWorker.ready;
      
      const token = await getToken(this.messaging, {
        vapidKey: 'your-vapid-key', // Get this from Firebase Console > Project Settings > Cloud Messaging
        serviceWorkerRegistration: this.registration
      });
      
      return token;
    } catch (error) {
      console.error('Error getting FCM token:', error);
      return null;
    }
  }

  async registerDeviceToken(userId, userType, authToken) {
    try {
      const fcmToken = await this.getFCMToken();
      if (!fcmToken) {
        throw new Error('Failed to get FCM token');
      }

      const response = await fetch('/api/notification/register-device-token', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${authToken}`
        },
        body: JSON.stringify({
          deviceToken: fcmToken,
          userType: userType
        })
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const result = await response.json();
      console.log('Device token registered successfully:', result);
      return result;
    } catch (error) {
      console.error('Error registering device token:', error);
      throw error;
    }
  }

  setupMessageListener() {
    onMessage(this.messaging, (payload) => {
      console.log('Message received in foreground:', payload);
      
      // Handle foreground messages
      if (payload.notification) {
        // You can show a custom notification here
        const notification = new Notification(payload.notification.title, {
          body: payload.notification.body,
          icon: '/icon-192x192.png',
          data: payload.data
        });

        notification.onclick = () => {
          window.focus();
          notification.close();
          // Handle notification click
          if (payload.data && payload.data.link) {
            window.location.href = payload.data.link;
          }
        };
      }
    });
  }
}

export default PushNotificationManager;
```

## Step 4: Usage in Your Application

```javascript
// In your main application file
import PushNotificationManager from './push-notification-manager.js';

const pushManager = new PushNotificationManager();

// Initialize push notifications when user logs in
async function initializePushNotifications(userId, userType, authToken) {
  try {
    const token = await pushManager.initialize();
    if (token) {
      await pushManager.registerDeviceToken(userId, userType, authToken);
      pushManager.setupMessageListener();
      console.log('Push notifications initialized successfully');
    }
  } catch (error) {
    console.error('Failed to initialize push notifications:', error);
  }
}

// Call this after successful login
// initializePushNotifications(userId, userType, authToken);
```

## Step 5: HTML Setup

Make sure your HTML includes the service worker registration:

```html
<!DOCTYPE html>
<html>
<head>
  <title>Your App</title>
  <!-- Add your app icons -->
  <link rel="icon" type="image/png" sizes="192x192" href="/icon-192x192.png">
  <link rel="icon" type="image/png" sizes="72x72" href="/badge-72x72.png">
</head>
<body>
  <!-- Your app content -->
  
  <script>
    // Register service worker
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/firebase-messaging-sw.js')
          .then((registration) => {
            console.log('SW registered: ', registration);
          })
          .catch((registrationError) => {
            console.log('SW registration failed: ', registrationError);
          });
      });
    }
  </script>
</body>
</html>
```

## Step 6: Get VAPID Key

1. Go to Firebase Console
2. Select your project
3. Go to Project Settings > Cloud Messaging
4. Generate a new key pair under "Web configuration"
5. Copy the key and replace `your-vapid-key` in the code

## Common Issues and Solutions

### 1. "Cannot read properties of undefined (reading 'pushManager')"
- **Cause**: Service worker not properly registered or Firebase not initialized
- **Solution**: Ensure service worker is registered before trying to get FCM token

### 2. "Messaging: This browser doesn't support the API's required to use the firebase SDK"
- **Cause**: Browser doesn't support service workers or push notifications
- **Solution**: Check browser compatibility and ensure HTTPS is used

### 3. "Messaging: We are unable to register the default service worker"
- **Cause**: Service worker file not found or incorrect path
- **Solution**: Ensure `firebase-messaging-sw.js` is in the public directory

### 4. "Messaging: A problem occurred while trying to retrieve the token"
- **Cause**: Invalid VAPID key or Firebase configuration
- **Solution**: Verify VAPID key and Firebase configuration

## Testing

1. Open browser developer tools
2. Check console for any errors
3. Verify service worker is registered in Application tab
4. Test notification permission in browser settings
5. Send a test notification from your backend

## Security Notes

- Never expose your Firebase configuration in client-side code in production
- Use environment variables for sensitive configuration
- Implement proper error handling and user feedback
- Consider implementing token refresh logic for long-lived sessions

