Skip to content

How to navigate user to a specific screen when they click on notification? #1214

@sanaf1333

Description

@sanaf1333

I have integrated FCM and notifee in my react-native app to display notifications. The problem is that when i click on notification on emulator (whether app is in foreground or background), it takes me to a specific screen. But when I do this on real device, it doesn't redirect me to a specific screen, only opens app if app is in background or stays on same screen if app is in foreground. Can someone please help me in figuring out what I am doing wrong or how can I achieve the emulator behaviour on real device?
Here is my relevant code snippet, I have wrapped my app in the Notification Provider

const NotificationProvider: React.FC<NotificationProviderProps> = ({
  children,
}) => {
  const messaging = getMessaging();

  const requestUserPermission = async () => {
    try {
      if (isAndroid()) {
        PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
        );
      }
      const authStatus = await requestPermission(messaging, {
        alert: true,
        badge: true,
        sound: true,
      });
      const enabled =
        authStatus === AuthorizationStatus.AUTHORIZED ||
        authStatus === AuthorizationStatus.PROVISIONAL;
      if (enabled) {
        if (isIos()) {
          const apnsToken = await getAPNSToken(messaging);
          if (apnsToken) {
            await setAPNSToken(messaging, apnsToken);
          } else {
            throw new Error("Failed to get APNs token");
          }
        }

        const fcmToken = await getToken(messaging);
        setToken(fcmToken);
        if (
          fcmToken &&
          isLoggedIn &&
          fcmToken !== user?.deviceToken &&
          user?.isMobileNotificationEnabled
        ) {
          EnableNotifications({ payload: { deviceToken: fcmToken } });
        } else {
          //   throw new Error("Failed to get FCM token");
        }
      }
    } catch (error) {
      console.log(error, "error request permisson");
    }
  };

  const handleNotificationLink = async (
    link: string,
    investorID: string,
    notificationID: string
  ) => {
    const storedUser = await localStore.getString(LOCAL_STORE_KEY.USER);
    const userData = user ? user : storedUser ? JSON.parse(storedUser) : null;

    if (!userData) {
      router.push("/auth/signIn");
      return;
    }
    if (!link) return;
    if (userData?.ID !== investorID) {
      return;
    }
    markNotificationAsRead({
      payload: {
        notificationIds: [notificationID],
      },
    });

    try {
      const baseUrl = "https://dev-investor-portal-fe.carbontech.build";
      const path = link.replace(baseUrl, "");

      const pathSegments = path.split("/").filter(Boolean);

      if (pathSegments.length === 0) return;

      const screen = pathSegments[0];
      const id = pathSegments[1] || null;

      if (id) {
        if (screen === NOTIFICATION_LINKS.OFFERS) {
          router.push({
            pathname: "/offers/OfferDetails",
            params: { offerID: id },
          });
        } else if (screen === NOTIFICATION_LINKS.INVESTMENTS) {
          router.push({
            pathname: "/dashboard/InvestmentDetailsFP",
            params: { investmentID: id },
          });
        } else if (screen === NOTIFICATION_LINKS.INVESTMENT) {
          const data = await fetchInvestmentHistory(id);
          if (data) {
            router.push({
              pathname: "/dashboard/TransactionDetailView",
              params: {
                investmentID: data?.investmentTrailExternalID,
                requestType: data?.requestType,
                date: formatDate(data?.createdAt),
                amount: data?.amount,
                accruedInterest: data?.accruedInterest,
                roi: data?.roi,
                status: data?.status,
                payments: JSON.stringify(data?.payments),
                investmentTrailID: data?.investmentTrailID,
              },
            });
          } else {
            showToast(
              "info",
              "Information for this request is no longer available"
            );
          }
        }
      } else {
        if (screen === NOTIFICATION_LINKS.MAKE_INVESTMNET) {
          router.push("/make-investment");
        } else if (screen === NOTIFICATION_LINKS.OFFERS) {
          router.push(TAB_ROUTES.OFFERS_TAB);
        } else if (screen === NOTIFICATION_LINKS.INVESTMENTS) {
          router.push(TAB_ROUTES.OFFERS_TAB); //TO-DO double check this later
        }
      }
    } catch (error) {
      console.error("Error parsing notification link:", error);
    }
  };

  useEffect(() => {
    notifee.onBackgroundEvent(async ({ type, detail }) => {
      switch (type) {
        case EventType.PRESS:
          //mutate({ payload: { notificationIds: [detail?.notification?.data?.notificationID] } });
          const storedUser = await localStore.getString(LOCAL_STORE_KEY.USER);
          const userData = storedUser ? JSON.parse(storedUser) : null;
          if (!userData) {
            router.push("/auth/signIn");
            return;
          }
          handleNotificationLink(
            detail?.notification?.data?.url! as string,
            detail?.notification?.data?.investorID! as string,
            detail?.notification?.data?.notificationID as string
          );
          break;
      }
    });
    const unsubscribe = notifee.onForegroundEvent(async ({ type, detail }) => {
      switch (type) {
        case EventType.PRESS:
          const storedUser = await localStore.getString(LOCAL_STORE_KEY.USER);
          const userData = storedUser ? JSON.parse(storedUser) : null;
          if (!userData) {
            router.push("/auth/signIn");
            return;
          }
          handleNotificationLink(
            detail?.notification?.data?.url! as string,
            detail?.notification?.data?.investorID! as string,
            detail?.notification?.data?.notificationID as string
          );
          break;
      }
    });
    return () => unsubscribe();
  }, []);

  useEffect(() => {
    getInitialNotification(messaging).then((remoteMessage) => {
      if (remoteMessage) {
        handleNotificationLink(
          remoteMessage?.data?.link! as string,
          remoteMessage?.data?.investorID! as string,
          remoteMessage?.data?.notificationID as string
        );
      }
    });
  }, []);

  useEffect(() => {
    requestUserPermission();

    // Setup foreground message listener
    const unsubscribe = onMessage(messaging, async (remoteMessage) => {
      console.log("Received FCM message in foreground:", remoteMessage);
      await refetch();

      // Create (or ensure) a notification channel (Android only)
      const channelId = await notifee.createChannel({
        id: "default",
        name: "Default Channel",
        importance: AndroidImportance.HIGH,
      });

      // Display the notification using Notifee
      await notifee.displayNotification({
        title: remoteMessage.notification?.title,
        body: remoteMessage.notification?.body,
        data: remoteMessage.data,
        android: {
          channelId,
          smallIcon: "ic_large_icon",
          badgeCount: notificationCount,
          pressAction: {
            id: "default",
            launchActivity: "default",
          },
        },
        ios: {
          badgeCount: notificationCount,
        },
      });
    });
    setBackgroundMessageHandler(messaging, async (remoteMessage) => {
      await refetch();
    });

    onNotificationOpenedApp(messaging, async (remoteMessage) => {
      console.log("on notification opened app", remoteMessage);
      handleNotificationLink(
        remoteMessage?.data?.url as string,
        remoteMessage?.data?.investorID! as string,
        remoteMessage?.data?.notificationID as string
      );
    });

    return () => unsubscribe();
  }, []);

  return (
    <NotificationContext.Provider value={{ notificationCount }}>
      {children}
    </NotificationContext.Provider>
  );
};

export default NotificationProvider;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions