Browse Source

notifications test

Viktoriia 11 months ago
parent
commit
3201df25c1

+ 9 - 5
Route.tsx

@@ -124,10 +124,14 @@ const Route = () => {
   const checkNmToken = async () => {
     if (token && uid) {
       try {
-        const response = await axios.postForm(API_URL + '/' + API.CHECK_TOKEN, {
-          token,
-          user_id: +uid
-        });
+        const response = await axios.postForm(
+          API_URL + '/' + API.CHECK_TOKEN,
+          {
+            token,
+            user_id: +uid
+          },
+          { headers: { 'Cache-Control': 'no-cache' } }
+        );
 
         if (response.data.result !== 'OK') {
           handleLogout();
@@ -163,7 +167,7 @@ const Route = () => {
 
   useEffect(() => {
     const prepareApp = async () => {
-      // checkTokenAndUpdate();
+      checkTokenAndUpdate();
       await checkNmToken();
       await findFastestServer();
       await openDatabases();

+ 1 - 0
app.config.ts

@@ -75,6 +75,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
         apiKey: env.ANDROID_GOOGLE_MAP_APIKEY
       },
     },
+    googleServicesFile: './google-services.json',
     permissions: [
       // 'ACCESS_BACKGROUND_LOCATION',
       'ACCESS_FINE_LOCATION',

+ 112 - 1
src/components/MenuDrawer/index.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
-import { View, Image, Linking, Text } from 'react-native';
+import { View, Image, Linking, Text, Switch, Platform } from 'react-native';
 import { CommonActions, useNavigation } from '@react-navigation/native';
+import * as Notifications from 'expo-notifications';
 
 import { WarningModal } from '../WarningModal';
 import { MenuButton } from '../MenuButton';
@@ -18,6 +19,7 @@ import InfoIcon from 'assets/icons/info-solid.svg';
 
 import { APP_VERSION, FASTEST_MAP_HOST } from 'src/constants';
 import { useNotification } from 'src/contexts/NotificationContext';
+import { usePostSaveNotificationTokenMutation } from '@api/user';
 
 export const MenuDrawer = (props: any) => {
   const { mutate: deleteUser } = useDeleteUserMutation();
@@ -30,6 +32,11 @@ export const MenuDrawer = (props: any) => {
     action: () => {}
   });
   const { updateNotificationStatus } = useNotification();
+  const { mutateAsync: saveNotificationToken } = usePostSaveNotificationTokenMutation();
+  const [isSubscribed, setIsSubscribed] = useState(
+    (storage.get('subscribed', StoreType.BOOLEAN) as boolean) ?? false
+  );
+  const [shouldOpenWarningModal, setShouldOpenWarningModal] = useState(false);
 
   const openModal = (type: string, message: string, action: any) => {
     setModalInfo({
@@ -63,6 +70,84 @@ export const MenuDrawer = (props: any) => {
     deleteUser({ token }, { onSuccess: handleLogout });
   };
 
+  const handleSubscribe = async () => {
+    const deviceData = await registerForPushNotificationsAsync();
+
+    if (deviceData?.notificationToken) {
+      storage.set('subscribed', true);
+      setIsSubscribed(true);
+      await saveNotificationToken({
+        token,
+        platform: deviceData.platform,
+        n_token: deviceData.notificationToken
+      });
+
+      Notifications.addNotificationReceivedListener((notification) => {
+        console.log('notification', notification);
+      });
+
+      Notifications.addNotificationResponseReceivedListener((response) => {
+        const data = response.notification.request.content.data;
+        console.log('data', data);
+      });
+    }
+  };
+
+  const toggleSwitch = async () => {
+    if (isSubscribed) {
+      storage.set('subscribed', false);
+      storage.remove('deviceToken');
+      setIsSubscribed(false);
+    } else {
+      const { status } = await Notifications.getPermissionsAsync();
+      if (status !== 'granted') {
+        setModalInfo({
+          visible: true,
+          type: 'success',
+          message:
+            'To use this feature we need your permission to access your notifications. If you press OK your system will ask you to confirm permission to receive notifications from NomadMania.',
+          action: () => setShouldOpenWarningModal(true)
+        });
+      } else {
+        handleSubscribe();
+      }
+    }
+  };
+
+  async function registerForPushNotificationsAsync() {
+    const { status: existingStatus } = await Notifications.getPermissionsAsync();
+    let finalStatus = existingStatus;
+    if (existingStatus !== 'granted') {
+      const { status } = await Notifications.requestPermissionsAsync();
+      finalStatus = status;
+    }
+    if (finalStatus !== 'granted') {
+      setModalInfo({
+        visible: true,
+        type: 'success',
+        message:
+          'NomadMania app needs notification permissions to function properly. Open settings?',
+        action: () =>
+          Platform.OS === 'ios' ? Linking.openURL('app-settings:') : Linking.openSettings()
+      });
+      return null;
+    }
+    const deviceData = await Notifications.getDevicePushTokenAsync();
+    console.log('deviceData', deviceData);
+
+    if (Platform.OS === 'android') {
+      Notifications.setNotificationChannelAsync('default', {
+        name: 'default',
+        importance: Notifications.AndroidImportance.MAX,
+        vibrationPattern: [0, 250, 250, 250],
+        lightColor: '#FF231F7C'
+      });
+    }
+    storage.set('deviceToken', deviceData.data);
+
+    return { notificationToken: deviceData.data ?? '', platform: deviceData.type ?? '' };
+  }
+
   return (
     <>
       <View style={styles.container}>
@@ -88,6 +173,26 @@ export const MenuDrawer = (props: any) => {
             red={false}
             buttonFn={() => Linking.openURL('https://nomadmania.com/terms/')}
           />
+          <View
+            style={{
+              display: 'flex',
+              flexDirection: 'row',
+              justifyContent: 'space-between',
+              marginTop: 20,
+              alignItems: 'center'
+            }}
+          >
+            <Text style={{ color: Colors.DARK_BLUE, fontSize: 16, fontWeight: 'bold' }}>
+              Notifications
+            </Text>
+            <Switch
+              trackColor={{ false: Colors.LIGHT_GRAY, true: Colors.DARK_BLUE }}
+              thumbColor={Colors.WHITE}
+              onValueChange={toggleSwitch}
+              value={isSubscribed}
+              style={{ transform: 'scale(0.8)' }}
+            />
+          </View>
         </View>
 
         <View style={styles.bottomMenu}>
@@ -135,6 +240,12 @@ export const MenuDrawer = (props: any) => {
           modalInfo.action();
           closeModal();
         }}
+        onModalHide={() => {
+          if (shouldOpenWarningModal) {
+            setShouldOpenWarningModal(false);
+            handleSubscribe();
+          }
+        }}
       />
     </>
   );

+ 1 - 0
src/modules/api/user/queries/index.ts

@@ -6,3 +6,4 @@ export * from './use-post-get-profile-regions';
 export * from './use-post-get-profile-data';
 export * from './use-post-get-profile-updates';
 export * from './use-post-get-map-years';
+export * from './use-post-save-notification-token';

+ 30 - 0
src/modules/api/user/queries/use-post-save-notification-token.tsx

@@ -0,0 +1,30 @@
+import { useMutation } from '@tanstack/react-query';
+
+import { userQueryKeys } from '../user-query-keys';
+import { userApi } from '../user-api';
+import { ResponseType } from '@api/response-type';
+
+import type { BaseAxiosError } from '../../../../types';
+
+export const usePostSaveNotificationTokenMutation = () => {
+  return useMutation<
+    ResponseType,
+    BaseAxiosError,
+    {
+      token: string;
+      platform: string;
+      n_token: string;
+    },
+    ResponseType
+  >({
+    mutationKey: userQueryKeys.setNotificationToken(),
+    mutationFn: async (variables) => {
+      const response = await userApi.setNotificationToken(
+        variables.token,
+        variables.platform,
+        variables.n_token
+      );
+      return response.data;
+    }
+  });
+};

+ 7 - 1
src/modules/api/user/user-api.tsx

@@ -326,5 +326,11 @@ export const userApi = {
       profile_id
     }),
   getMapYears: (profile_id: number) =>
-    request.postForm<PostGetMapYearsReturn>(API.GET_MAP_YEARS, { profile_id })
+    request.postForm<PostGetMapYearsReturn>(API.GET_MAP_YEARS, { profile_id }),
+  setNotificationToken: (token: string, platform: string, n_token: string) =>
+    request.postForm<ResponseType>(API.SET_NOTIFICATION_TOKEN, {
+      token,
+      platform,
+      n_token
+    })
 };

+ 2 - 1
src/modules/api/user/user-query-keys.tsx

@@ -6,5 +6,6 @@ export const userQueryKeys = {
   getProfileRegions: (uid: number, type: string) => ['getProfileRegions', uid, type] as const,
   getProfileInfoData: (userId: number) => ['getProfileInfoData', userId] as const,
   getProfileUpdates: (userId: number) => ['getProfileUpdates', userId] as const,
-  getMapYears: (userId: number) => ['getMapYears', userId] as const
+  getMapYears: (userId: number) => ['getMapYears', userId] as const,
+  setNotificationToken: () => ['setNotificationToken'] as const
 };