Skip to main content

Notification Setup

This guide covers setting up push notifications for both Android (FCM) and iOS (APNs).

Overview

Twigz supports both Firebase Cloud Messaging (FCM) and Apple Push Notifications (APNs) for cross-platform push notifications.

Android Setup (FCM)

1. Firebase Project Setup

  1. Go to Firebase Console
  2. Create a new project or select existing
  3. Add Android app with your package name
  4. Download google-services.json

2. Install Dependencies

npm install firebase

3. Initialize Firebase

import { initializeApp } from 'firebase/app';
import { getMessaging, getToken } from 'firebase/messaging';

const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "your-project.firebaseapp.com",
  projectId: "your-project-id",
  storageBucket: "your-project.appspot.com",
  messagingSenderId: "123456789",
  appId: "your-app-id"
};

const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);

4. Get FCM Token

// Get FCM token
const getFCMToken = async () => {
  try {
    const token = await getToken(messaging, {
      vapidKey: 'your-vapid-key'
    });
    
    // Send token to your backend
    await convex.mutation(api.shared.notifications.recordNativeDeviceToken, {
      token,
      platform: "android"
    });
    
    return token;
  } catch (error) {
    console.error('Error getting FCM token:', error);
  }
};

iOS Setup (APNs)

1. Apple Developer Account

  1. Go to Apple Developer Portal
  2. Create App ID with Push Notifications capability
  3. Generate APNs certificate or key
  4. Configure your app for push notifications

2. Install Dependencies

npm install @react-native-async-storage/async-storage

3. Request Permission

import { requestPermissions } from 'react-native-permissions';

const requestNotificationPermission = async () => {
  const result = await requestPermissions({
    ios: ['alert', 'badge', 'sound'],
  });
  
  return result.ios.status === 'granted';
};

4. Get APNs Token

import messaging from '@react-native-firebase/messaging';

const getAPNsToken = async () => {
  try {
    const token = await messaging().getToken();
    
    // Send token to your backend
    await convex.mutation(api.shared.notifications.recordNativeDeviceToken, {
      token,
      platform: "ios"
    });
    
    return token;
  } catch (error) {
    console.error('Error getting APNs token:', error);
  }
};

Sending Notifications

From Backend

// Send FCM notification
await convex.mutation(api.shared.notifications.sendFCMNotificationDirect, {
  token: "fcm_token_here",
  title: "New Order!",
  body: "You have received a new order",
  data: {
    orderId: "order_123",
    type: "order"
  }
});

// Send APNs notification
await convex.mutation(api.shared.notifications.sendAPNsNotificationDirect, {
  token: "apns_token_here",
  title: "Order Update",
  body: "Your order status has changed",
  data: {
    orderId: "order_123",
    type: "order_update"
  }
});

Bulk Notifications

// Send to multiple users
await convex.mutation(api.shared.notifications.sendBulkNotification, {
  userIds: ["user_1", "user_2", "user_3"],
  title: "Special Offer!",
  body: "20% off all products today only",
  data: {
    type: "promotion",
    discount: "20"
  }
});

Notification Types

Order Notifications

// New order notification
const sendNewOrderNotification = async (storeId: string, orderId: string) => {
  const store = await convex.query(api.stores.queries.getStoreByAuthenticatedOwner, {
    storeId
  });
  
  if (store?.deviceTokens?.length) {
    await convex.mutation(api.shared.notifications.sendNotificationToUser, {
      userId: store.ownerId,
      title: "New Order Received!",
      body: `Order #${orderId} is ready for processing`,
      data: { orderId, type: "new_order" }
    });
  }
};

Price Change Notifications

// Price change notification
const sendPriceChangeNotification = async (productId: string, oldPrice: number, newPrice: number) => {
  const product = await convex.query(api.shared.products.getProductById, { productId });
  
  if (product?.likedBy?.length) {
    await convex.mutation(api.shared.notifications.sendBulkNotification, {
      userIds: product.likedBy,
      title: "Price Drop Alert!",
      body: `${product.name} price dropped from ${oldPrice} to ${newPrice} AED`,
      data: { productId, type: "price_change" }
    });
  }
};

Testing Notifications

Test Notification

// Send test notification
await convex.mutation(api.shared.notifications.sendTestNotification, {
  userId: "user_123",
  title: "Test Notification",
  body: "This is a test notification"
});

Debug Notifications

// Debug user notifications
const debugInfo = await convex.query(api.shared.notifications.debugUserNotifications, {
  userId: "user_123"
});

console.log("User tokens:", debugInfo.tokens);
console.log("Recent notifications:", debugInfo.recentNotifications);

Best Practices

  1. Request permission before sending notifications
  2. Handle token refresh for long-lived apps
  3. Personalize notifications based on user preferences
  4. Test thoroughly on both platforms
  5. Monitor delivery rates and user engagement
Always test notifications on real devices as simulators may not support all notification features.