123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- import React, { useEffect, useState, useContext, createContext } from 'react';
- import * as Notifications from 'expo-notifications';
- import { storage, StoreType } from 'src/storage';
- import { AppState, AppStateStatus, Linking, Platform } from 'react-native';
- import { CommonActions, useNavigation } from '@react-navigation/native';
- import { NAVIGATION_PAGES } from 'src/types';
- import { usePostSetSettingsMutation } from '@api/notifications';
- import { useMessagesStore } from 'src/stores/unreadMessagesStore';
- import { useFriendsNotificationsStore } from 'src/stores/friendsNotificationsStore';
- import {
- handleNotificationData,
- registerBackgroundNotificationTask,
- unregisterBackgroundNotificationTask
- } from 'src/utils/pushNotificationTask';
- const PushNotificationContext = createContext<{
- isSubscribed: boolean;
- toggleSubscription: () => Promise<void>;
- unsubscribeFromNotifications: () => Promise<void>;
- }>({
- isSubscribed: false,
- toggleSubscription: async () => {},
- unsubscribeFromNotifications: async () => {}
- });
- export const usePushNotification = () => useContext(PushNotificationContext);
- export const PushNotificationProvider = ({ children }: { children: React.ReactNode }) => {
- const token = storage.get('token', StoreType.STRING) as string;
- const [isSubscribed, setIsSubscribed] = useState(
- (storage.get('subscribed', StoreType.BOOLEAN) as boolean) ?? false
- );
- const { mutateAsync: setNotificationsSettings } = usePostSetSettingsMutation();
- const navigation = useNavigation();
- const updateNotificationStatus = useFriendsNotificationsStore(
- (state) => state.updateNotificationStatus
- );
- const updateUnreadMessagesCount = useMessagesStore((state) => state.updateUnreadMessagesCount);
- const [appState, setAppState] = useState(AppState.currentState);
- const lastNotificationResponse = Notifications.useLastNotificationResponse();
- useEffect(() => {
- const handleAppStateChange = (nextAppState: AppStateStatus) => {
- if (appState.match(/inactive|background/) && nextAppState === 'active' && isSubscribed) {
- Notifications.getBadgeCountAsync().then((badgeCount) => {
- if (badgeCount > 0) {
- Notifications.setBadgeCountAsync(-1);
- }
- });
- Notifications.getPresentedNotificationsAsync().then((notifications) => {
- if (Platform.OS === 'ios' && notifications.length > 0) {
- notifications.forEach((notification) => {
- let groupToken;
- let messageId;
- let fromUser;
- const parsedData =
- JSON.parse(
- (notification.request.trigger as Notifications.PushNotificationTrigger)?.payload
- ?.params as string
- ) ?? {};
- groupToken = parsedData?.group_token;
- messageId = (notification.request.trigger as Notifications.PushNotificationTrigger)
- ?.payload?.message_id as number;
- fromUser = parsedData?.id;
- handleNotificationData(groupToken, messageId, fromUser);
- });
- }
- });
- updateNotificationStatus();
- updateUnreadMessagesCount();
- }
- setAppState(nextAppState);
- };
- const subscription = AppState.addEventListener('change', handleAppStateChange);
- return () => {
- subscription.remove();
- };
- }, [appState]);
- useEffect(() => {
- if (lastNotificationResponse && Platform.OS === 'android') {
- const data = lastNotificationResponse.notification.request.content.data;
- if (data?.screen && data?.parentScreen) {
- if (data?.params) {
- const parsedParams = JSON.parse(data.params) ?? {};
- navigation.dispatch(
- CommonActions.reset({
- index: 1,
- routes: [
- {
- name: 'DrawerApp',
- state: {
- routes: [
- {
- name: data.parentScreen,
- state: {
- routes: [
- { name: NAVIGATION_PAGES.MAP_TAB },
- {
- name: data.screen,
- params: parsedParams
- }
- ]
- }
- }
- ]
- }
- }
- ]
- })
- );
- } else {
- navigation.dispatch(
- CommonActions.reset({
- index: 1,
- routes: [
- {
- name: 'DrawerApp',
- state: {
- routes: [
- {
- name: data.parentScreen,
- state: {
- routes: [
- { name: NAVIGATION_PAGES.MAP_TAB },
- {
- name: data.screen
- }
- ]
- }
- }
- ]
- }
- }
- ]
- })
- );
- }
- }
- if (data?.url) {
- Linking.openURL(data.url);
- }
- }
- }, [lastNotificationResponse]);
- const checkNotificationPermissions = async () => {
- const { status } = await Notifications.getPermissionsAsync();
- return status;
- };
- useEffect(() => {
- const getPermissionsStatus = async () => {
- const status = await checkNotificationPermissions();
- if (status !== 'granted' && isSubscribed) {
- await unsubscribeFromNotifications();
- return;
- }
- };
- if (isSubscribed) {
- getPermissionsStatus();
- Notifications.setNotificationHandler({
- handleNotification: async () => ({
- shouldShowAlert: true,
- shouldPlaySound: false,
- shouldSetBadge: false
- })
- });
- registerBackgroundNotificationTask();
- const notificationListener = Notifications.addNotificationReceivedListener((notification) => {
- updateNotificationStatus();
- updateUnreadMessagesCount();
- let groupToken;
- let messageId;
- let fromUser;
- if (Platform.OS === 'ios') {
- const parsedData =
- JSON.parse(
- (notification.request.trigger as Notifications.PushNotificationTrigger)?.payload
- ?.params as string
- ) ?? {};
- groupToken = parsedData?.group_token;
- messageId = (notification.request.trigger as Notifications.PushNotificationTrigger)
- ?.payload?.message_id as number;
- fromUser = parsedData?.id;
- handleNotificationData(groupToken, messageId, fromUser);
- }
- });
- const responseListener = Notifications.addNotificationResponseReceivedListener((response) => {
- let screenName;
- let url;
- let parentScreen;
- let params;
- if (Platform.OS === 'ios') {
- parentScreen = (
- response.notification.request.trigger as Notifications.PushNotificationTrigger
- )?.payload?.parentScreen;
- screenName = (
- response.notification.request.trigger as Notifications.PushNotificationTrigger
- )?.payload?.screen;
- params = (response.notification.request.trigger as Notifications.PushNotificationTrigger)
- ?.payload?.params;
- url = (response.notification.request.trigger as Notifications.PushNotificationTrigger)
- ?.payload?.url;
- }
- if (screenName && parentScreen) {
- if (params) {
- const parsedParams = JSON.parse(params as string) ?? {};
- navigation.dispatch(
- CommonActions.reset({
- index: 1,
- routes: [
- {
- name: 'DrawerApp',
- state: {
- routes: [
- {
- name: parentScreen as string,
- state: {
- routes: [
- { name: NAVIGATION_PAGES.MAP_TAB },
- {
- name: screenName as string,
- params: parsedParams
- }
- ]
- }
- }
- ]
- }
- }
- ]
- })
- );
- } else {
- navigation.dispatch(
- CommonActions.reset({
- index: 1,
- routes: [
- {
- name: 'DrawerApp',
- state: {
- routes: [
- {
- name: parentScreen as string,
- state: {
- routes: [
- { name: NAVIGATION_PAGES.MAP_TAB },
- {
- name: screenName as string
- }
- ]
- }
- }
- ]
- }
- }
- ]
- })
- );
- }
- }
- if (url) {
- Linking.openURL(url as string);
- }
- });
- Notifications.getBadgeCountAsync().then((badgeCount) => {
- if (badgeCount > 0) {
- Notifications.setBadgeCountAsync(-1);
- }
- });
- return () => {
- notificationListener.remove();
- responseListener.remove();
- };
- } else {
- unregisterBackgroundNotificationTask();
- }
- }, [isSubscribed]);
- const subscribeToNotifications = async () => {
- storage.set('subscribed', true);
- setIsSubscribed(true);
- };
- const unsubscribeFromNotifications = async () => {
- const settings = {
- [Platform.OS === 'ios' ? 'app-ios' : 'app-android']: 0
- };
- await setNotificationsSettings({
- token,
- settings: JSON.stringify(settings)
- });
- storage.remove('deviceToken');
- storage.set('subscribed', false);
- setIsSubscribed(false);
- unregisterBackgroundNotificationTask();
- };
- const toggleSubscription = async () => {
- if (isSubscribed) {
- await unsubscribeFromNotifications();
- } else {
- await subscribeToNotifications();
- }
- };
- return (
- <PushNotificationContext.Provider
- value={{ isSubscribed, toggleSubscription, unsubscribeFromNotifications }}
- >
- {children}
- </PushNotificationContext.Provider>
- );
- };
|