浏览代码

chat screen refactor/android icon plugin/status bar translucent on map screen

Viktoriia 8 月之前
父节点
当前提交
249db2a208

+ 17 - 13
app.config.ts

@@ -10,7 +10,8 @@ const API_HOST = env.ENV === 'production' ? env.PRODUCTION_API_HOST : env.DEVELO
 const MAP_HOST = env.ENV === 'production' ? env.PRODUCTION_MAP_HOST : env.DEVELOPMENT_MAP_HOST;
 const MAP_HOST = env.ENV === 'production' ? env.PRODUCTION_MAP_HOST : env.DEVELOPMENT_MAP_HOST;
 
 
 const GOOGLE_MAP_PLACES_APIKEY = env.GOOGLE_MAP_PLACES_APIKEY;
 const GOOGLE_MAP_PLACES_APIKEY = env.GOOGLE_MAP_PLACES_APIKEY;
-const WEBSOCKET_URL = env.ENV === 'production' ? env.PRODUCTION_WEBSOCKET_URL : env.DEVELOPMENT_WEBSOCKET_URL;
+const WEBSOCKET_URL =
+  env.ENV === 'production' ? env.PRODUCTION_WEBSOCKET_URL : env.DEVELOPMENT_WEBSOCKET_URL;
 
 
 dotenv.config({
 dotenv.config({
   path: path.resolve(process.cwd(), '.env')
   path: path.resolve(process.cwd(), '.env')
@@ -54,7 +55,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
     url: 'https://u.expo.dev/c31c6828-3c32-4c7a-aabc-f9b8336b3b66'
     url: 'https://u.expo.dev/c31c6828-3c32-4c7a-aabc-f9b8336b3b66'
   },
   },
   platforms: ['ios', 'android'],
   platforms: ['ios', 'android'],
-  assetBundlePatterns: ['**/*', "assets/db/*.db"],
+  assetBundlePatterns: ['**/*', 'assets/db/*.db'],
   ios: {
   ios: {
     supportsTablet: false,
     supportsTablet: false,
     bundleIdentifier: env.PACKAGE_NAME_IOS, // com.nomadmania.app2
     bundleIdentifier: env.PACKAGE_NAME_IOS, // com.nomadmania.app2
@@ -72,11 +73,13 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
       NSPushNotificationsDescription:
       NSPushNotificationsDescription:
         'This will allow NomadMania.com to send you notifications. Also you can disable it in app settings',
         'This will allow NomadMania.com to send you notifications. Also you can disable it in app settings',
 
 
-      NSMicrophoneUsageDescription: "Nomadmania app needs access to the microphone to record audio.",
-      NSDocumentsFolderUsageDescription: "Nomadmania app needs access to the documents folder to select files.",
-      NSCameraUsageDescription: "Nomadmania app needs access to the camera to record video.",
+      NSMicrophoneUsageDescription:
+        'Nomadmania app needs access to the microphone to record audio.',
+      NSDocumentsFolderUsageDescription:
+        'Nomadmania app needs access to the documents folder to select files.',
+      NSCameraUsageDescription: 'Nomadmania app needs access to the camera to record video.',
       NSLocationWhenInUseUsageDescription:
       NSLocationWhenInUseUsageDescription:
-        'NomadMania app needs access to your location to show relevant data.',
+        'NomadMania app needs access to your location to show relevant data.'
     },
     },
     privacyManifests: {
     privacyManifests: {
       NSPrivacyAccessedAPITypes: [
       NSPrivacyAccessedAPITypes: [
@@ -105,7 +108,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
       'USER_FACING_NOTIFICATIONS',
       'USER_FACING_NOTIFICATIONS',
       'INTERNET',
       'INTERNET',
       'CAMERA',
       'CAMERA',
-      "RECORD_AUDIO",
+      'RECORD_AUDIO',
       'MODIFY_AUDIO_SETTINGS'
       'MODIFY_AUDIO_SETTINGS'
     ],
     ],
     versionCode: 74 // next version submitted to Google Play needs to be higher than that 2.0.21
     versionCode: 74 // next version submitted to Google Play needs to be higher than that 2.0.21
@@ -140,18 +143,19 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
       'expo-asset',
       'expo-asset',
       {
       {
         assets: [
         assets: [
-          "./assets/db/nmRegions.db",
-          "./assets/db/darePlaces.db",
-          "./assets/db/nmCountries.db"
+          './assets/db/nmRegions.db',
+          './assets/db/darePlaces.db',
+          './assets/db/nmCountries.db'
         ]
         ]
       }
       }
     ],
     ],
     'expo-font',
     'expo-font',
     [
     [
-      "expo-av",
+      'expo-av',
       {
       {
-        "microphonePermission": "Allow Nomadmania to access your microphone."
+        microphonePermission: 'Allow Nomadmania to access your microphone.'
       }
       }
-    ]
+    ],
+    ['@react-native-firebase/messaging']
   ]
   ]
 });
 });

+ 3 - 2
package.json

@@ -16,6 +16,7 @@
     "@react-native-clipboard/clipboard": "^1.14.2",
     "@react-native-clipboard/clipboard": "^1.14.2",
     "@react-native-community/datetimepicker": "8.0.1",
     "@react-native-community/datetimepicker": "8.0.1",
     "@react-native-community/netinfo": "11.3.1",
     "@react-native-community/netinfo": "11.3.1",
+    "@react-native-firebase/messaging": "^21.2.0",
     "@react-navigation/bottom-tabs": "^6.5.11",
     "@react-navigation/bottom-tabs": "^6.5.11",
     "@react-navigation/drawer": "^6.6.15",
     "@react-navigation/drawer": "^6.6.15",
     "@react-navigation/material-top-tabs": "^6.6.5",
     "@react-navigation/material-top-tabs": "^6.6.5",
@@ -63,8 +64,8 @@
     "react-native-gesture-handler": "~2.16.1",
     "react-native-gesture-handler": "~2.16.1",
     "react-native-get-random-values": "^1.11.0",
     "react-native-get-random-values": "^1.11.0",
     "react-native-gifted-chat": "^2.6.3",
     "react-native-gifted-chat": "^2.6.3",
-    "react-native-haptic-feedback": "^2.3.2",
     "react-native-google-places-autocomplete": "^2.5.7",
     "react-native-google-places-autocomplete": "^2.5.7",
+    "react-native-haptic-feedback": "^2.3.2",
     "react-native-image-viewing": "^0.2.2",
     "react-native-image-viewing": "^0.2.2",
     "react-native-keyboard-aware-scroll-view": "^0.9.5",
     "react-native-keyboard-aware-scroll-view": "^0.9.5",
     "react-native-linear-gradient": "^2.8.3",
     "react-native-linear-gradient": "^2.8.3",
@@ -86,8 +87,8 @@
     "react-native-tab-view": "^3.5.2",
     "react-native-tab-view": "^3.5.2",
     "react-native-video": "^6.5.0",
     "react-native-video": "^6.5.0",
     "react-native-view-shot": "^3.7.0",
     "react-native-view-shot": "^3.7.0",
-    "react-native-wheel-pick": "^1.2.2",
     "react-native-walkthrough-tooltip": "^1.6.0",
     "react-native-walkthrough-tooltip": "^1.6.0",
+    "react-native-wheel-pick": "^1.2.2",
     "uuid": "^10.0.0",
     "uuid": "^10.0.0",
     "yup": "^1.3.3",
     "yup": "^1.3.3",
     "zustand": "^4.4.7"
     "zustand": "^4.4.7"

+ 10 - 5
src/modules/api/auth/auth-api.ts

@@ -28,11 +28,16 @@ export const authApi = {
     const formData = new FormData();
     const formData = new FormData();
 
 
     formData.append('user', JSON.stringify(data.user));
     formData.append('user', JSON.stringify(data.user));
-    formData.append('photo', {
-      type: data.photo.type,
-      uri: data.photo.uri,
-      name: data.photo.name
-    } as unknown as Blob);
+    if (data.photo && data.photo?.uri) {
+      formData.append('photo', {
+        type:
+          data.photo.type === 'image'
+            ? data.photo.type + '/' + data.photo.uri.split('.').pop()!
+            : data.photo.type,
+        uri: data.photo.uri,
+        name: data.photo.name
+      } as unknown as Blob);
+    }
 
 
     return request.postForm<PostRegisterUserReturn>(API.REGISTER, formData);
     return request.postForm<PostRegisterUserReturn>(API.REGISTER, formData);
   },
   },

+ 6 - 1
src/modules/api/chat/chat-api.ts

@@ -62,6 +62,10 @@ export interface PostSendMessage {
   reply_to_id?: number;
   reply_to_id?: number;
 }
 }
 
 
+export interface PostSendMessageReturn extends ResponseType {
+  message_id: number;
+}
+
 export interface PostMessagesReceivedOrRead {
 export interface PostMessagesReceivedOrRead {
   token: string;
   token: string;
   from_user: number;
   from_user: number;
@@ -128,7 +132,8 @@ export const chatApi = {
       no_of_messages,
       no_of_messages,
       previous_than_message_id
       previous_than_message_id
     }),
     }),
-  sendMessage: (data: PostSendMessage) => request.postForm<ResponseType>(API.SEND_MESSAGE, data),
+  sendMessage: (data: PostSendMessage) =>
+    request.postForm<PostSendMessageReturn>(API.SEND_MESSAGE, data),
   messagesReceived: (data: PostMessagesReceivedOrRead) =>
   messagesReceived: (data: PostMessagesReceivedOrRead) =>
     request.postForm<ResponseType>(API.MESSAGES_RECEIVED, data),
     request.postForm<ResponseType>(API.MESSAGES_RECEIVED, data),
   messagesRead: (data: PostMessagesReceivedOrRead) =>
   messagesRead: (data: PostMessagesReceivedOrRead) =>

+ 9 - 8
src/modules/api/chat/queries/use-post-send-message.tsx

@@ -1,17 +1,18 @@
 import { useMutation } from '@tanstack/react-query';
 import { useMutation } from '@tanstack/react-query';
 
 
 import { chatQueryKeys } from '../chat-query-keys';
 import { chatQueryKeys } from '../chat-query-keys';
-import { chatApi, type PostSendMessage } from '../chat-api';
+import { chatApi, type PostSendMessage, type PostSendMessageReturn } from '../chat-api';
 
 
 import type { BaseAxiosError } from '../../../../types';
 import type { BaseAxiosError } from '../../../../types';
-import { ResponseType } from '@api/response-type';
 
 
 export const usePostSendMessageMutation = () => {
 export const usePostSendMessageMutation = () => {
-  return useMutation<ResponseType, BaseAxiosError, PostSendMessage, ResponseType>({
-    mutationKey: chatQueryKeys.sendMessage(),
-    mutationFn: async (data) => {
-      const response = await chatApi.sendMessage(data);
-      return response.data;
+  return useMutation<PostSendMessageReturn, BaseAxiosError, PostSendMessage, PostSendMessageReturn>(
+    {
+      mutationKey: chatQueryKeys.sendMessage(),
+      mutationFn: async (data) => {
+        const response = await chatApi.sendMessage(data);
+        return response.data;
+      }
     }
     }
-  });
+  );
 };
 };

+ 3 - 1
src/screens/InAppScreens/MapScreen/index.tsx

@@ -7,7 +7,8 @@ import {
   TextInput,
   TextInput,
   TouchableOpacity,
   TouchableOpacity,
   View,
   View,
-  Image
+  Image,
+  StatusBar
 } from 'react-native';
 } from 'react-native';
 import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
 import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
 import MapView, { Geojson, Marker, UrlTile } from 'react-native-maps';
 import MapView, { Geojson, Marker, UrlTile } from 'react-native-maps';
@@ -868,6 +869,7 @@ const MapScreen: React.FC<MapScreenProps> = ({ navigation, route }) => {
 
 
   return (
   return (
     <View style={styles.container}>
     <View style={styles.container}>
+      <StatusBar translucent backgroundColor="transparent" />
       <ClusteredMapView
       <ClusteredMapView
         region={initialRegion}
         region={initialRegion}
         ref={mapRef}
         ref={mapRef}

+ 1 - 0
src/screens/InAppScreens/MapScreen/style.tsx

@@ -7,6 +7,7 @@ export const styles = StyleSheet.create({
     ...StyleSheet.absoluteFillObject,
     ...StyleSheet.absoluteFillObject,
     alignItems: 'center',
     alignItems: 'center',
     justifyContent: 'flex-end',
     justifyContent: 'flex-end',
+    paddingTop: 0
   },
   },
   map: {
   map: {
     ...StyleSheet.absoluteFillObject,
     ...StyleSheet.absoluteFillObject,

+ 254 - 282
src/screens/InAppScreens/MessagesScreen/ChatScreen/index.tsx

@@ -17,7 +17,6 @@ import {
   GiftedChat,
   GiftedChat,
   Bubble,
   Bubble,
   InputToolbar,
   InputToolbar,
-  Actions,
   IMessage,
   IMessage,
   Send,
   Send,
   BubbleProps,
   BubbleProps,
@@ -26,13 +25,7 @@ import {
   MessageProps
   MessageProps
 } from 'react-native-gifted-chat';
 } from 'react-native-gifted-chat';
 import { MaterialCommunityIcons } from '@expo/vector-icons';
 import { MaterialCommunityIcons } from '@expo/vector-icons';
-import * as ImagePicker from 'expo-image-picker';
-import { useActionSheet } from '@expo/react-native-action-sheet';
-import {
-  GestureHandlerRootView,
-  LongPressGestureHandler,
-  Swipeable
-} from 'react-native-gesture-handler';
+import { GestureHandlerRootView, Swipeable } from 'react-native-gesture-handler';
 import { AvatarWithInitials, Header, WarningModal } from 'src/components';
 import { AvatarWithInitials, Header, WarningModal } from 'src/components';
 import { Colors } from 'src/theme';
 import { Colors } from 'src/theme';
 import { useFocusEffect, useNavigation } from '@react-navigation/native';
 import { useFocusEffect, useNavigation } from '@react-navigation/native';
@@ -55,7 +48,6 @@ import {
 } from '@api/chat';
 } from '@api/chat';
 import { CustomMessage, Message, Reaction } from '../types';
 import { CustomMessage, Message, Reaction } from '../types';
 import { API_HOST, WEBSOCKET_URL } from 'src/constants';
 import { API_HOST, WEBSOCKET_URL } from 'src/constants';
-import { getFontSize } from 'src/utils';
 import ReactionBar from '../Components/ReactionBar';
 import ReactionBar from '../Components/ReactionBar';
 import OptionsMenu from '../Components/OptionsMenu';
 import OptionsMenu from '../Components/OptionsMenu';
 import EmojiSelectorModal from '../Components/EmojiSelectorModal';
 import EmojiSelectorModal from '../Components/EmojiSelectorModal';
@@ -63,9 +55,9 @@ import { styles } from './styles';
 import SendIcon from 'assets/icons/messages/send.svg';
 import SendIcon from 'assets/icons/messages/send.svg';
 import { SheetManager } from 'react-native-actions-sheet';
 import { SheetManager } from 'react-native-actions-sheet';
 import { NAVIGATION_PAGES } from 'src/types';
 import { NAVIGATION_PAGES } from 'src/types';
-import * as Notifications from 'expo-notifications';
 import { usePushNotification } from 'src/contexts/PushNotificationContext';
 import { usePushNotification } from 'src/contexts/PushNotificationContext';
 import ReactionsListModal from '../Components/ReactionsListModal';
 import ReactionsListModal from '../Components/ReactionsListModal';
+import { dismissChatNotifications } from '../utils';
 
 
 const options = {
 const options = {
   enableVibrateFallback: true,
   enableVibrateFallback: true,
@@ -75,14 +67,15 @@ const options = {
 const reactionEmojis = ['👍', '❤️', '😂', '😮', '😭'];
 const reactionEmojis = ['👍', '❤️', '😂', '😮', '😭'];
 
 
 const ChatScreen = ({ route }: { route: any }) => {
 const ChatScreen = ({ route }: { route: any }) => {
+  const token = storage.get('token', StoreType.STRING) as string;
   const { id, name, avatar }: { id: number; name: string; avatar: string | null } = route.params;
   const { id, name, avatar }: { id: number; name: string; avatar: string | null } = route.params;
+
   const currentUserId = storage.get('uid', StoreType.STRING) as number;
   const currentUserId = storage.get('uid', StoreType.STRING) as number;
-  const token = storage.get('token', StoreType.STRING) as string;
   const insets = useSafeAreaInsets();
   const insets = useSafeAreaInsets();
   const [messages, setMessages] = useState<CustomMessage[] | null>();
   const [messages, setMessages] = useState<CustomMessage[] | null>();
-  const { showActionSheetWithOptions } = useActionSheet();
   const navigation = useNavigation();
   const navigation = useNavigation();
-  const { data: chatData, isFetching, refetch } = usePostGetChatWithQuery(token, id, -1, -1, true);
+  const [prevThenMessageId, setPrevThenMessageId] = useState<number>(-1);
+  const { data: chatData } = usePostGetChatWithQuery(token, id, 50, prevThenMessageId, true); // to do cache
   const { mutateAsync: sendMessage } = usePostSendMessageMutation();
   const { mutateAsync: sendMessage } = usePostSendMessageMutation();
 
 
   const swipeableRowRef = useRef<Swipeable | null>(null);
   const swipeableRowRef = useRef<Swipeable | null>(null);
@@ -121,6 +114,8 @@ const ChatScreen = ({ route }: { route: any }) => {
   const flatList = useRef<FlatList | null>(null);
   const flatList = useRef<FlatList | null>(null);
   const scrollY = useSharedValue(0);
   const scrollY = useSharedValue(0);
   const { isSubscribed } = usePushNotification();
   const { isSubscribed } = usePushNotification();
+  const [isLoadingEarlier, setIsLoadingEarlier] = useState(false);
+  const [hasMoreMessages, setHasMoreMessages] = useState(true);
 
 
   const socket = useRef<WebSocket | null>(null);
   const socket = useRef<WebSocket | null>(null);
 
 
@@ -128,103 +123,11 @@ const ChatScreen = ({ route }: { route: any }) => {
     setModalInfo({ ...modalInfo, visible: false });
     setModalInfo({ ...modalInfo, visible: false });
   };
   };
 
 
-  const dismissChatNotifications = async (chatWithUserId: number) => {
-    const { status } = await Notifications.getPermissionsAsync();
-    if (status !== 'granted' || !isSubscribed) {
-      setModalInfo({
-        visible: true,
-        type: 'success',
-        message:
-          'To use this feature we need your permission to access your notifications. You will be redirected to the notification settings screen where you need to enable them.',
-        action: () =>
-          // @ts-ignore
-          navigation.navigate(NAVIGATION_PAGES.MENU_DRAWER, {
-            screen: NAVIGATION_PAGES.NOTIFICATIONS
-          })
-      });
-      return;
-    }
-
-    const getNotificationData = (notification: Notifications.Notification) => {
-      if (Platform.OS === 'android') {
-        const data = notification.request.content.data;
-        if (data?.params) {
-          try {
-            return JSON.parse(data.params) ?? {};
-          } catch (error) {
-            console.error('Error parsing params:', error);
-            return {};
-          }
-        } else {
-          Notifications.dismissNotificationAsync(notification.request.identifier);
-          return {};
-        }
-      } else {
-        const data = (notification.request.trigger as Notifications.PushNotificationTrigger)
-          ?.payload;
-        if (data?.params) {
-          try {
-            return JSON.parse(data.params as string) ?? {};
-          } catch (error) {
-            console.error('Error parsing params:', error);
-            return {};
-          }
-        }
-      }
-    };
-
-    const clearNotificationsFromUser = async (userId: number) => {
-      const presentedNotifications = await Notifications.getPresentedNotificationsAsync();
-      presentedNotifications.forEach((notification) => {
-        const parsedParams = getNotificationData(notification);
-        const conversation_with_user = parsedParams?.id;
-
-        if (conversation_with_user === userId) {
-          Notifications.dismissNotificationAsync(notification.request.identifier);
-        }
-      });
-    };
-
-    await clearNotificationsFromUser(chatWithUserId);
-
-    Notifications.setNotificationHandler({
-      handleNotification: async (notification) => {
-        let conversation_with_user = 0;
-        const parsedParams = getNotificationData(notification);
-        conversation_with_user = parsedParams?.id;
-
-        if (conversation_with_user === chatWithUserId) {
-          return {
-            shouldShowAlert: false,
-            shouldPlaySound: false,
-            shouldSetBadge: false
-          };
-        }
-
-        return {
-          shouldShowAlert: true,
-          shouldPlaySound: false,
-          shouldSetBadge: false
-        };
-      }
-    });
-
-    return () => {
-      Notifications.setNotificationHandler({
-        handleNotification: async () => ({
-          shouldShowAlert: true,
-          shouldPlaySound: false,
-          shouldSetBadge: false
-        })
-      });
-    };
-  };
-
   useEffect(() => {
   useEffect(() => {
     let unsubscribe: any;
     let unsubscribe: any;
 
 
     const setupNotificationHandler = async () => {
     const setupNotificationHandler = async () => {
-      unsubscribe = await dismissChatNotifications(id);
+      unsubscribe = await dismissChatNotifications(id, isSubscribed, setModalInfo, navigation);
     };
     };
 
 
     setupNotificationHandler();
     setupNotificationHandler();
@@ -251,40 +154,188 @@ const ChatScreen = ({ route }: { route: any }) => {
     };
     };
 
 
     return () => {
     return () => {
-      socket.current?.close();
+      if (socket.current) {
+        socket.current.close();
+        socket.current = null;
+      }
     };
     };
   }, [token]);
   }, [token]);
 
 
   const handleWebSocketMessage = (data: any) => {
   const handleWebSocketMessage = (data: any) => {
     switch (data.action) {
     switch (data.action) {
       case 'new_message':
       case 'new_message':
-        if (data.conversation_with === id) {
-          refetch();
+        if (data.conversation_with === id && data.message) {
+          const newMessage = mapApiMessageToGiftedMessage(data.message);
+          setMessages((previousMessages) => {
+            const messageExists =
+              previousMessages && previousMessages.some((msg) => msg._id === newMessage._id);
+            if (!messageExists) {
+              return GiftedChat.append(previousMessages ?? [], [newMessage]);
+            }
+            return previousMessages;
+          });
+        }
+        break;
+
+      case 'new_reaction':
+        if (data.conversation_with === id && data.reaction) {
+          updateMessageWithReaction(data.reaction);
+        }
+        break;
+
+      case 'unreact':
+        if (data.conversation_with === id && data.unreacted_message_id) {
+          removeReactionFromMessage(data.unreacted_message_id);
+        }
+        break;
+
+      case 'delete_message':
+        if (data.conversation_with === id && data.deleted_message_id) {
+          removeDeletedMessage(data.deleted_message_id);
         }
         }
         break;
         break;
+
       case 'is_typing':
       case 'is_typing':
         if (data.conversation_with === id) {
         if (data.conversation_with === id) {
           setIsTyping(true);
           setIsTyping(true);
         }
         }
         break;
         break;
+
       case 'stopped_typing':
       case 'stopped_typing':
         if (data.conversation_with === id) {
         if (data.conversation_with === id) {
           setIsTyping(false);
           setIsTyping(false);
         }
         }
         break;
         break;
-      case 'new_reaction':
-        if (data.conversation_with === id) {
-          refetch();
+
+      case 'messages_read':
+        if (data.conversation_with === id && data.read_messages_ids) {
+          setMessages(
+            (prevMessages) =>
+              prevMessages?.map((msg) => {
+                if (data.read_messages_ids.includes(msg._id)) {
+                  return { ...msg, received: true };
+                }
+                return msg;
+              }) ?? []
+          );
         }
         }
         break;
         break;
+
       default:
       default:
         break;
         break;
     }
     }
   };
   };
 
 
-  const sendWebSocketMessage = (action: string) => {
+  const updateMessageWithReaction = (reactionData: any) => {
+    setMessages(
+      (prevMessages) =>
+        prevMessages?.map((msg) => {
+          if (msg._id === reactionData.message_id) {
+            const updatedReactions = [
+              ...(Array.isArray(msg.reactions)
+                ? msg.reactions?.filter((r: any) => r.uid !== reactionData.uid)
+                : []),
+              reactionData
+            ];
+            return { ...msg, reactions: updatedReactions };
+          }
+          return msg;
+        }) ?? []
+    );
+  };
+
+  const removeReactionFromMessage = (messageId: number) => {
+    setMessages(
+      (prevMessages) =>
+        prevMessages?.map((msg) => {
+          if (msg._id === messageId) {
+            const updatedReactions = Array.isArray(msg.reactions)
+              ? msg.reactions?.filter((r: any) => r.uid !== id)
+              : [];
+            return { ...msg, reactions: updatedReactions };
+          }
+          return msg;
+        }) ?? []
+    );
+  };
+
+  const removeDeletedMessage = (messageId: number) => {
+    setMessages(
+      (prevMessages) =>
+        prevMessages?.map((msg) => {
+          if (msg._id === messageId) {
+            return {
+              ...msg,
+              deleted: true,
+              text: 'This message was deleted',
+              pending: false,
+              sent: false,
+              received: false
+            };
+          }
+          return msg;
+        }) ?? []
+    );
+  };
+
+  useEffect(() => {
+    const pingInterval = setInterval(() => {
+      if (socket.current && socket.current.readyState === WebSocket.OPEN) {
+        socket.current.send(JSON.stringify({ action: 'ping', conversation_with: id }));
+      }
+    }, 50000);
+
+    return () => clearInterval(pingInterval);
+  }, []);
+
+  const sendWebSocketMessage = (
+    action: string,
+    message: CustomMessage | null = null,
+    reaction: string | null = null,
+    readMessagesIds: number[] | null = null
+  ) => {
     if (socket.current && socket.current.readyState === WebSocket.OPEN) {
     if (socket.current && socket.current.readyState === WebSocket.OPEN) {
-      socket.current.send(JSON.stringify({ action, conversation_with: id }));
+      const data: any = {
+        action,
+        conversation_with: id
+      };
+
+      if (action === 'new_message' && message) {
+        data.message = {
+          id: message._id,
+          text: message.text,
+          sender: +currentUserId,
+          sent_datetime: new Date().toISOString().replace('T', ' ').substring(0, 19),
+          reply_to_id: message.replyMessage?.id ?? -1,
+          reply_to: message.replyMessage ?? null,
+          reactions: message.reactions ?? '{}',
+          status: 2,
+          attachement: -1
+        };
+      }
+
+      if (action === 'new_reaction' && message && reaction) {
+        data.reaction = {
+          message_id: message._id,
+          reaction,
+          uid: +currentUserId,
+          datetime: new Date().toISOString()
+        };
+      }
+
+      if (action === 'unreact' && message) {
+        data.message_id = message._id;
+      }
+
+      if (action === 'delete_message' && message) {
+        data.message_id = message._id;
+      }
+
+      if (action === 'messages_read' && readMessagesIds) {
+        data.messages_ids = readMessagesIds;
+      }
+
+      socket.current.send(JSON.stringify(data));
     }
     }
   };
   };
 
 
@@ -346,11 +397,35 @@ const ChatScreen = ({ route }: { route: any }) => {
             setUnreadMessageIndex(0);
             setUnreadMessageIndex(0);
           }
           }
         }
         }
-        setMessages(mappedMessages);
+
+        setMessages((previousMessages) => {
+          const newMessages = mappedMessages.filter(
+            (newMsg) => !previousMessages?.some((oldMsg) => oldMsg._id === newMsg._id)
+          );
+          return prevThenMessageId !== -1 && previousMessages
+            ? GiftedChat.prepend(previousMessages, newMessages)
+            : mappedMessages;
+        });
+
+        if (mappedMessages.length < 50) {
+          setHasMoreMessages(false);
+        }
+
+        setIsLoadingEarlier(false);
       }
       }
     }, [chatData])
     }, [chatData])
   );
   );
 
 
+  const loadEarlierMessages = async () => {
+    if (!hasMoreMessages || isLoadingEarlier || !messages) return;
+
+    setIsLoadingEarlier(true);
+
+    const previousMessageId = messages[messages.length - 1]._id;
+
+    setPrevThenMessageId(previousMessageId);
+  };
+
   const sentToServer = useRef<Set<number>>(new Set());
   const sentToServer = useRef<Set<number>>(new Set());
 
 
   const handleViewableItemsChanged = ({ viewableItems }: { viewableItems: any[] }) => {
   const handleViewableItemsChanged = ({ viewableItems }: { viewableItems: any[] }) => {
@@ -373,10 +448,9 @@ const ChatScreen = ({ route }: { route: any }) => {
           messages_id: newViewableUnreadMessages
           messages_id: newViewableUnreadMessages
         },
         },
         {
         {
-          onSuccess: (res) => {
+          onSuccess: () => {
             newViewableUnreadMessages.forEach((id) => sentToServer.current.add(id));
             newViewableUnreadMessages.forEach((id) => sentToServer.current.add(id));
-            // sendWebSocketMessage('messages_read');
-            sendWebSocketMessage('new_message');
+            sendWebSocketMessage('messages_read', null, null, newViewableUnreadMessages);
           }
           }
         }
         }
       );
       );
@@ -467,12 +541,26 @@ const ChatScreen = ({ route }: { route: any }) => {
       },
       },
       {
       {
         onSuccess: () => {
         onSuccess: () => {
-          setMessages((prevMessages) =>
-            prevMessages ? prevMessages.filter((msg) => msg._id !== messageId) : []
+          setMessages(
+            (prevMessages) =>
+              prevMessages?.map((msg) => {
+                if (msg._id === messageId) {
+                  return {
+                    ...msg,
+                    deleted: true,
+                    text: 'This message was deleted',
+                    pending: false,
+                    sent: false,
+                    received: false
+                  };
+                }
+                return msg;
+              }) ?? []
           );
           );
-          // sendWebSocketMessage('message_deleted');
-          refetch();
-          sendWebSocketMessage('new_message');
+          const messageToDelete = messages?.find((msg) => msg._id === messageId);
+          if (messageToDelete) {
+            sendWebSocketMessage('delete_message', messageToDelete, null, null);
+          }
         }
         }
       }
       }
     );
     );
@@ -534,30 +622,20 @@ const ChatScreen = ({ route }: { route: any }) => {
 
 
     return (
     return (
       <View
       <View
-        style={{
-          flexDirection: 'row',
-          justifyContent: hasReactions ? 'space-between' : 'flex-end',
-          alignItems: 'center',
-          paddingHorizontal: 8,
-          paddingBottom: 6,
-          flexShrink: 1,
-          flexGrow: 1,
-          gap: 12
-        }}
+        style={[
+          styles.bottomContainer,
+          {
+            justifyContent: hasReactions ? 'space-between' : 'flex-end'
+          }
+        ]}
       >
       >
         {hasReactions && (
         {hasReactions && (
           <TouchableOpacity
           <TouchableOpacity
             style={[
             style={[
+              styles.bottomCustomContainer,
               {
               {
-                flexDirection: 'row',
-                alignItems: 'center',
-                flexShrink: 0,
                 backgroundColor:
                 backgroundColor:
-                  time.position === 'left' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.2)',
-                borderRadius: 12,
-                paddingHorizontal: 6,
-                paddingVertical: 4,
-                gap: 6
+                  time.position === 'left' ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.2)'
               }
               }
             ]}
             ]}
             onPress={() =>
             onPress={() =>
@@ -597,25 +675,8 @@ const ChatScreen = ({ route }: { route: any }) => {
             })}
             })}
           </TouchableOpacity>
           </TouchableOpacity>
         )}
         )}
-        <View
-          style={{
-            flexDirection: 'row',
-            gap: 4,
-            alignItems: 'center',
-            alignSelf: 'flex-end'
-          }}
-        >
-          <Text
-            style={{
-              color: Colors.LIGHT_GRAY,
-              fontSize: getFontSize(10),
-              fontWeight: '600',
-              paddingLeft: 8,
-              flexShrink: 0
-            }}
-          >
-            {formattedTime}
-          </Text>
+        <View style={styles.timeContainer}>
+          <Text style={styles.timeText}>{formattedTime}</Text>
           {renderTicks(time.currentMessage)}
           {renderTicks(time.currentMessage)}
         </View>
         </View>
       </View>
       </View>
@@ -678,6 +739,8 @@ const ChatScreen = ({ route }: { route: any }) => {
       }
       }
       const message = { ...newMessages[0], pending: true };
       const message = { ...newMessages[0], pending: true };
 
 
+      setMessages((previousMessages) => GiftedChat.append(previousMessages ?? [], [message]));
+
       sendMessage(
       sendMessage(
         {
         {
           token,
           token,
@@ -686,118 +749,29 @@ const ChatScreen = ({ route }: { route: any }) => {
           reply_to_id: replyMessage ? (replyMessage._id as number) : -1
           reply_to_id: replyMessage ? (replyMessage._id as number) : -1
         },
         },
         {
         {
-          onSuccess: () => sendWebSocketMessage('new_message'),
+          onSuccess: (res) => {
+            const newMessage = {
+              _id: res.message_id,
+              text: message.text,
+              replyMessage: { ...message.replyMessage, sender: replyMessage?.user?._id }
+            };
+
+            setMessages((previousMessages) =>
+              (previousMessages ?? []).map((msg) =>
+                msg._id === message._id ? { ...msg, _id: res.message_id } : msg
+              )
+            );
+            sendWebSocketMessage('new_message', newMessage as unknown as CustomMessage);
+          },
           onError: (err) => console.log('err', err)
           onError: (err) => console.log('err', err)
         }
         }
       );
       );
 
 
-      setMessages((previousMessages) => GiftedChat.append(previousMessages ?? [], [message]));
       clearReplyMessage();
       clearReplyMessage();
     },
     },
     [replyMessage]
     [replyMessage]
   );
   );
 
 
-  const openActionSheet = () => {
-    const options = ['Open Camera', 'Select from gallery', 'Cancel'];
-    const cancelButtonIndex = 2;
-
-    showActionSheetWithOptions(
-      {
-        options,
-        cancelButtonIndex
-      },
-      async (buttonIndex) => {
-        if (buttonIndex === 0) {
-          openCamera();
-        } else if (buttonIndex === 1) {
-          openGallery();
-        }
-      }
-    );
-  };
-
-  const openCamera = async () => {
-    const permissionResult = await ImagePicker.requestCameraPermissionsAsync();
-
-    if (permissionResult.granted === false) {
-      alert('Permission denied to access camera');
-      return;
-    }
-
-    const result = await ImagePicker.launchCameraAsync({
-      mediaTypes: ImagePicker.MediaTypeOptions.All,
-      quality: 1,
-      allowsEditing: true
-    });
-
-    if (!result.canceled) {
-      const newMedia = {
-        _id: Date.now().toString(),
-        createdAt: new Date(),
-        user: { _id: +currentUserId, name: 'Me' },
-        image: result.assets[0].type === 'image' ? result.assets[0].uri : null,
-        video: result.assets[0].type === 'video' ? result.assets[0].uri : null
-      };
-      setMessages((previousMessages) =>
-        GiftedChat.append(previousMessages ?? [], [newMedia as any])
-      );
-    }
-  };
-
-  const openGallery = async () => {
-    const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
-
-    if (permissionResult.granted === false) {
-      alert('Denied');
-      return;
-    }
-
-    const result = await ImagePicker.launchImageLibraryAsync({
-      mediaTypes: ImagePicker.MediaTypeOptions.All,
-      allowsMultipleSelection: true,
-      quality: 1
-    });
-
-    if (!result.canceled && result.assets) {
-      const imageMessages = result.assets.map((asset) => ({
-        _id: Date.now().toString() + asset.uri,
-        createdAt: new Date(),
-        user: { _id: +currentUserId, name: 'Me' },
-        image: asset.type === 'image' ? asset.uri : null,
-        video: asset.type === 'video' ? asset.uri : null
-      }));
-
-      setMessages((previousMessages) =>
-        GiftedChat.append(previousMessages ?? [], imageMessages as any[])
-      );
-    }
-  };
-
-  const renderMessageVideo = (props: BubbleProps<CustomMessage>) => {
-    const { currentMessage } = props;
-
-    if (currentMessage.video) {
-      return (
-        <LongPressGestureHandler
-          onHandlerStateChange={(event) => handleLongPress(currentMessage, props)}
-        >
-          <TouchableOpacity
-            onPress={() => setSelectedMedia(currentMessage.video)}
-            style={styles.mediaContainer}
-          >
-            <Video
-              source={{ uri: currentMessage.video }}
-              style={styles.chatMedia}
-              useNativeControls
-            />
-          </TouchableOpacity>
-        </LongPressGestureHandler>
-      );
-    }
-
-    return null;
-  };
-
   const addReaction = (messageId: number, reaction: string) => {
   const addReaction = (messageId: number, reaction: string) => {
     if (!messages) return;
     if (!messages) return;
 
 
@@ -823,7 +797,12 @@ const ChatScreen = ({ route }: { route: any }) => {
     reactToMessage(
     reactToMessage(
       { token, message_id: messageId, reaction: reaction, conversation_with_user: id },
       { token, message_id: messageId, reaction: reaction, conversation_with_user: id },
       {
       {
-        onSuccess: () => sendWebSocketMessage('new_reaction'),
+        onSuccess: () => {
+          const message = messages.find((msg) => msg._id === messageId);
+          if (message) {
+            sendWebSocketMessage('new_reaction', message, reaction);
+          }
+        },
         onError: (err) => console.log('err', err)
         onError: (err) => console.log('err', err)
       }
       }
     );
     );
@@ -1063,14 +1042,7 @@ const ChatScreen = ({ route }: { route: any }) => {
   const renderScrollToBottom = () => {
   const renderScrollToBottom = () => {
     return (
     return (
       <TouchableOpacity
       <TouchableOpacity
-        style={{
-          position: 'absolute',
-          bottom: -20,
-          right: -20,
-          backgroundColor: Colors.DARK_BLUE,
-          borderRadius: 20,
-          padding: 8
-        }}
+        style={styles.scrollToBottom}
         onPress={() => {
         onPress={() => {
           if (flatList.current) {
           if (flatList.current) {
             flatList.current.scrollToIndex({ index: 0, animated: true });
             flatList.current.scrollToIndex({ index: 0, animated: true });
@@ -1164,15 +1136,7 @@ const ChatScreen = ({ route }: { route: any }) => {
             onInputTextChanged={(text) => handleTyping(text.length > 0)}
             onInputTextChanged={(text) => handleTyping(text.length > 0)}
             isTyping={isTyping}
             isTyping={isTyping}
             renderSend={(props) => (
             renderSend={(props) => (
-              <View
-                style={{
-                  flexDirection: 'row',
-                  height: '100%',
-                  alignItems: 'center',
-                  justifyContent: 'center',
-                  paddingHorizontal: 14
-                }}
-              >
+              <View style={styles.sendBtn}>
                 {props.text?.trim() && (
                 {props.text?.trim() && (
                   <Send
                   <Send
                     {...props}
                     {...props}
@@ -1198,7 +1162,6 @@ const ChatScreen = ({ route }: { route: any }) => {
             renderChatFooter={() => (
             renderChatFooter={() => (
               <ReplyMessageBar clearReply={clearReplyMessage} message={replyMessage} />
               <ReplyMessageBar clearReply={clearReplyMessage} message={replyMessage} />
             )}
             )}
-            // renderMessageVideo={renderMessageVideo}
             renderAvatar={null}
             renderAvatar={null}
             maxComposerHeight={100}
             maxComposerHeight={100}
             renderComposer={(props) => <Composer {...props} />}
             renderComposer={(props) => <Composer {...props} />}
@@ -1225,6 +1188,15 @@ const ChatScreen = ({ route }: { route: any }) => {
                 }
                 }
               }
               }
             ]}
             ]}
+            infiniteScroll={true}
+            loadEarlier={hasMoreMessages}
+            isLoadingEarlier={isLoadingEarlier}
+            onLoadEarlier={loadEarlierMessages}
+            renderLoadEarlier={() => (
+              <View style={{ paddingVertical: 20 }}>
+                <ActivityIndicator size="small" color={Colors.DARK_BLUE} />
+              </View>
+            )}
           />
           />
         ) : (
         ) : (
           <ActivityIndicator size="large" color={Colors.DARK_BLUE} />
           <ActivityIndicator size="large" color={Colors.DARK_BLUE} />

+ 46 - 0
src/screens/InAppScreens/MessagesScreen/ChatScreen/styles.tsx

@@ -105,5 +105,51 @@ export const styles = StyleSheet.create({
     fontWeight: '600',
     fontWeight: '600',
     textAlign: 'center',
     textAlign: 'center',
     color: Colors.DARK_BLUE
     color: Colors.DARK_BLUE
+  },
+  scrollToBottom: {
+    position: 'absolute',
+    bottom: -20,
+    right: -20,
+    backgroundColor: Colors.DARK_BLUE,
+    borderRadius: 20,
+    padding: 8
+  },
+  sendBtn: {
+    flexDirection: 'row',
+    height: '100%',
+    alignItems: 'center',
+    justifyContent: 'center',
+    paddingHorizontal: 14
+  },
+  timeContainer: {
+    flexDirection: 'row',
+    gap: 4,
+    alignItems: 'center',
+    alignSelf: 'flex-end'
+  },
+  timeText: {
+    color: Colors.LIGHT_GRAY,
+    fontSize: getFontSize(10),
+    fontWeight: '600',
+    paddingLeft: 8,
+    flexShrink: 0
+  },
+  bottomContainer: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 8,
+    paddingBottom: 6,
+    flexShrink: 1,
+    flexGrow: 1,
+    gap: 12
+  },
+  bottomCustomContainer: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    flexShrink: 0,
+    borderRadius: 12,
+    paddingHorizontal: 6,
+    paddingVertical: 4,
+    gap: 6
   }
   }
 });
 });

+ 6 - 3
src/screens/InAppScreens/MessagesScreen/Components/ReactionsListModal.tsx

@@ -4,6 +4,7 @@ import ActionSheet, { SheetManager } from 'react-native-actions-sheet';
 import { usePostUnreactToMessageMutation } from '@api/chat';
 import { usePostUnreactToMessageMutation } from '@api/chat';
 import { getFontSize } from 'src/utils';
 import { getFontSize } from 'src/utils';
 import { Colors } from 'src/theme';
 import { Colors } from 'src/theme';
+import { CustomMessage } from '../types';
 
 
 const ReactionsListModal = () => {
 const ReactionsListModal = () => {
   const [reactionsData, setReactionsData] = useState<{
   const [reactionsData, setReactionsData] = useState<{
@@ -13,7 +14,7 @@ const ReactionsListModal = () => {
     messageId: number;
     messageId: number;
     conversation_with_user: number;
     conversation_with_user: number;
     setMessages: (messages: any) => void;
     setMessages: (messages: any) => void;
-    sendWebSocketMessage: (message: string) => void;
+    sendWebSocketMessage: (action: string, data: any) => void;
   } | null>(null);
   } | null>(null);
 
 
   const { mutateAsync: unreactToMessage } = usePostUnreactToMessageMutation();
   const { mutateAsync: unreactToMessage } = usePostUnreactToMessageMutation();
@@ -26,7 +27,7 @@ const ReactionsListModal = () => {
       messageId: number;
       messageId: number;
       conversation_with_user: number;
       conversation_with_user: number;
       setMessages: (messages: any) => void;
       setMessages: (messages: any) => void;
-      sendWebSocketMessage: (message: string) => void;
+      sendWebSocketMessage: (action: string, data: any) => void;
     } | null
     } | null
   ) => {
   ) => {
     setReactionsData(payload);
     setReactionsData(payload);
@@ -56,7 +57,9 @@ const ReactionsListModal = () => {
                 return msg;
                 return msg;
               })
               })
             );
             );
-            reactionsData.sendWebSocketMessage('new_reaction');
+            reactionsData.sendWebSocketMessage('unreact', {
+              _id: reactionsData.messageId
+            } as unknown as CustomMessage);
           }
           }
         }
         }
       );
       );

+ 12 - 9
src/screens/InAppScreens/MessagesScreen/index.tsx

@@ -1,12 +1,5 @@
 import React, { useState, useEffect, useRef, useCallback } from 'react';
 import React, { useState, useEffect, useRef, useCallback } from 'react';
-import {
-  View,
-  Text,
-  TouchableOpacity,
-  Image,
-  Platform,
-  TouchableHighlight,
-} from 'react-native';
+import { View, Text, TouchableOpacity, Image, Platform, TouchableHighlight } from 'react-native';
 import {
 import {
   AvatarWithInitials,
   AvatarWithInitials,
   HorizontalTabView,
   HorizontalTabView,
@@ -72,7 +65,6 @@ const MessagesScreen = () => {
   const [blocked, setBlocked] = useState<Blocked[]>([]);
   const [blocked, setBlocked] = useState<Blocked[]>([]);
   const updateUnreadMessagesCount = useMessagesStore((state) => state.updateUnreadMessagesCount);
   const updateUnreadMessagesCount = useMessagesStore((state) => state.updateUnreadMessagesCount);
 
 
-
   const [filteredChats, setFilteredChats] = useState<{
   const [filteredChats, setFilteredChats] = useState<{
     all: Chat[];
     all: Chat[];
     unread: Chat[];
     unread: Chat[];
@@ -109,9 +101,20 @@ const MessagesScreen = () => {
     }, 500);
     }, 500);
   };
   };
 
 
+  useEffect(() => {
+    const pingInterval = setInterval(() => {
+      if (socket.current && socket.current.readyState === WebSocket.OPEN) {
+        socket.current.send(JSON.stringify({ action: 'ping', conversation_with: 0 }));
+      }
+    }, 50000);
+
+    return () => clearInterval(pingInterval);
+  }, []);
+
   const handleWebSocketMessage = (data: any) => {
   const handleWebSocketMessage = (data: any) => {
     switch (data.action) {
     switch (data.action) {
       case 'new_message':
       case 'new_message':
+      case 'messages_read':
         refetch();
         refetch();
         break;
         break;
       case 'is_typing':
       case 'is_typing':

+ 100 - 0
src/screens/InAppScreens/MessagesScreen/utils.ts

@@ -1,4 +1,8 @@
 import moment from 'moment';
 import moment from 'moment';
+import * as Notifications from 'expo-notifications';
+import { Platform } from 'react-native';
+import { NAVIGATION_PAGES } from 'src/types';
+import { usePushNotification } from 'src/contexts/PushNotificationContext';
 
 
 export const formatDate = (dateString: Date): string => {
 export const formatDate = (dateString: Date): string => {
   const inputDate = moment.utc(dateString).local();
   const inputDate = moment.utc(dateString).local();
@@ -17,3 +21,99 @@ export const formatDate = (dateString: Date): string => {
 
 
   return inputDate.format('DD.MM');
   return inputDate.format('DD.MM');
 };
 };
+
+export const dismissChatNotifications = async (
+  chatWithUserId: number,
+  isSubscribed: boolean,
+  setModalInfo: (data: any) => void,
+  navigation: any
+) => {
+  const { status } = await Notifications.getPermissionsAsync();
+  if (status !== 'granted' || !isSubscribed) {
+    setModalInfo({
+      visible: true,
+      type: 'success',
+      message:
+        'To use this feature we need your permission to access your notifications. You will be redirected to the notification settings screen where you need to enable them.',
+      action: () =>
+        // @ts-ignore
+        navigation.navigate(NAVIGATION_PAGES.MENU_DRAWER, {
+          screen: NAVIGATION_PAGES.NOTIFICATIONS
+        })
+    });
+    return;
+  }
+
+  const getNotificationData = (notification: Notifications.Notification) => {
+    if (Platform.OS === 'android') {
+      const data = notification.request.content.data;
+      if (data?.params) {
+        try {
+          return JSON.parse(data.params) ?? {};
+        } catch (error) {
+          console.error('Error parsing params:', error);
+          return {};
+        }
+      } else {
+        Notifications.dismissNotificationAsync(notification.request.identifier);
+        return {};
+      }
+    } else {
+      const data = (notification.request.trigger as Notifications.PushNotificationTrigger)?.payload;
+      if (data?.params) {
+        try {
+          return JSON.parse(data.params as string) ?? {};
+        } catch (error) {
+          console.error('Error parsing params:', error);
+          return {};
+        }
+      }
+    }
+  };
+
+  const clearNotificationsFromUser = async (userId: number) => {
+    const presentedNotifications = await Notifications.getPresentedNotificationsAsync();
+    presentedNotifications.forEach((notification) => {
+      const parsedParams = getNotificationData(notification);
+      const conversation_with_user = parsedParams?.id;
+
+      if (conversation_with_user === userId) {
+        Notifications.dismissNotificationAsync(notification.request.identifier);
+      }
+    });
+  };
+
+  await clearNotificationsFromUser(chatWithUserId);
+
+  Notifications.setNotificationHandler({
+    handleNotification: async (notification) => {
+      let conversation_with_user = 0;
+      const parsedParams = getNotificationData(notification);
+      conversation_with_user = parsedParams?.id;
+
+      if (conversation_with_user === chatWithUserId) {
+        return {
+          shouldShowAlert: false,
+          shouldPlaySound: false,
+          shouldSetBadge: false
+        };
+      }
+
+      return {
+        shouldShowAlert: true,
+        shouldPlaySound: false,
+        shouldSetBadge: false
+      };
+    }
+  });
+
+  return () => {
+    Notifications.setNotificationHandler({
+      handleNotification: async () => ({
+        shouldShowAlert: true,
+        shouldPlaySound: false,
+        shouldSetBadge: false
+      })
+    });
+  };
+};

+ 6 - 2
src/screens/RegisterScreen/EditAccount/index.tsx

@@ -103,14 +103,18 @@ const EditAccount = () => {
               validationSchema={SignUpSchema}
               validationSchema={SignUpSchema}
               onSubmit={async (values) => {
               onSubmit={async (values) => {
                 setIsSubmitting(true);
                 setIsSubmitting(true);
+
+                const dateObject = new Date(values.date_of_birth);
+                const formattedDate = dateObject.toISOString().split('T')[0];
+
                 const data = {
                 const data = {
                   user: {
                   user: {
                     ...user,
                     ...user,
                     first_name: values.first_name,
                     first_name: values.first_name,
                     last_name: values.last_name,
                     last_name: values.last_name,
-                    date_of_birth: values.date_of_birth,
+                    date_of_birth: formattedDate,
                     homebase: values.homebase,
                     homebase: values.homebase,
-                    homebase2: values.homebase2
+                    homebase2: values.homebase2 ?? -1
                   },
                   },
                   photo: values.photo.uri
                   photo: values.photo.uri
                     ? {
                     ? {