Bladeren bron

app state fix for websockets

Viktoriia 8 maanden geleden
bovenliggende
commit
a70b15202c

+ 71 - 5
src/screens/InAppScreens/MessagesScreen/ChatScreen/index.tsx

@@ -10,8 +10,9 @@ import {
   Alert,
   ScrollView,
   Linking,
-  Platform,
-  ActivityIndicator
+  ActivityIndicator,
+  AppState,
+  AppStateStatus
 } from 'react-native';
 import {
   GiftedChat,
@@ -75,7 +76,11 @@ const ChatScreen = ({ route }: { route: any }) => {
   const [messages, setMessages] = useState<CustomMessage[] | null>();
   const navigation = useNavigation();
   const [prevThenMessageId, setPrevThenMessageId] = useState<number>(-1);
-  const { data: chatData } = usePostGetChatWithQuery(token, id, 50, prevThenMessageId, true); // to do cache
+  const {
+    data: chatData,
+    refetch,
+    isFetching
+  } = usePostGetChatWithQuery(token, id, 50, prevThenMessageId, true);
   const { mutateAsync: sendMessage } = usePostSendMessageMutation();
 
   const swipeableRowRef = useRef<Swipeable | null>(null);
@@ -117,6 +122,8 @@ const ChatScreen = ({ route }: { route: any }) => {
   const [isLoadingEarlier, setIsLoadingEarlier] = useState(false);
   const [hasMoreMessages, setHasMoreMessages] = useState(true);
 
+  const appState = useRef(AppState.currentState);
+
   const socket = useRef<WebSocket | null>(null);
 
   const closeModal = () => {
@@ -161,6 +168,35 @@ const ChatScreen = ({ route }: { route: any }) => {
     };
   }, [token]);
 
+  useEffect(() => {
+    const handleAppStateChange = async (nextAppState: AppStateStatus) => {
+      if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
+        if (!socket.current || socket.current.readyState === WebSocket.CLOSED) {
+          socket.current = new WebSocket(WEBSOCKET_URL);
+          socket.current.onopen = () => {
+            socket.current?.send(JSON.stringify({ token }));
+          };
+          socket.current.onmessage = (event) => {
+            const data = JSON.parse(event.data);
+            handleWebSocketMessage(data);
+          };
+        }
+
+        await dismissChatNotifications(id, isSubscribed, setModalInfo, navigation);
+      }
+    };
+
+    const subscription = AppState.addEventListener('change', handleAppStateChange);
+
+    return () => {
+      subscription.remove();
+      if (socket.current) {
+        socket.current.close();
+        socket.current = null;
+      }
+    };
+  }, [token]);
+
   const handleWebSocketMessage = (data: any) => {
     switch (data.action) {
       case 'new_message':
@@ -282,6 +318,22 @@ const ChatScreen = ({ route }: { route: any }) => {
     const pingInterval = setInterval(() => {
       if (socket.current && socket.current.readyState === WebSocket.OPEN) {
         socket.current.send(JSON.stringify({ action: 'ping', conversation_with: id }));
+      } else {
+        socket.current = new WebSocket(WEBSOCKET_URL);
+        socket.current.onopen = () => {
+          socket.current?.send(JSON.stringify({ token }));
+        };
+        socket.current.onmessage = (event) => {
+          const data = JSON.parse(event.data);
+          handleWebSocketMessage(data);
+        };
+
+        return () => {
+          if (socket.current) {
+            socket.current.close();
+            socket.current = null;
+          }
+        };
       }
     }, 50000);
 
@@ -373,12 +425,18 @@ const ChatScreen = ({ route }: { route: any }) => {
     };
   };
 
+  useFocusEffect(
+    useCallback(() => {
+      refetch();
+    }, [])
+  );
+
   useFocusEffect(
     useCallback(() => {
       if (chatData?.messages) {
         const mappedMessages = chatData.messages.map(mapApiMessageToGiftedMessage);
 
-        if (unreadMessageIndex === null && Platform.OS === 'ios') {
+        if (unreadMessageIndex === null && !isFetching) {
           const firstUnreadIndex = mappedMessages.findLastIndex(
             (msg) => !msg.received && !msg?.deleted && msg.user._id === id
           );
@@ -393,6 +451,15 @@ const ChatScreen = ({ route }: { route: any }) => {
             };
 
             mappedMessages.splice(firstUnreadIndex + 1, 0, unreadMarker);
+            setTimeout(() => {
+              if (flatList.current) {
+                flatList.current.scrollToIndex({
+                  index: firstUnreadIndex,
+                  animated: true,
+                  viewPosition: 0.5
+                });
+              }
+            }, 500);
           } else {
             setUnreadMessageIndex(0);
           }
@@ -1111,7 +1178,6 @@ const ChatScreen = ({ route }: { route: any }) => {
               initialNumToRender: 30,
               onViewableItemsChanged: handleViewableItemsChanged,
               viewabilityConfig: { itemVisiblePercentThreshold: 50 },
-              initialScrollIndex: unreadMessageIndex ?? 0,
               onScrollToIndexFailed: (info: any) => {
                 const wait = new Promise((resolve) => setTimeout(resolve, 300));
                 wait.then(() => {

+ 48 - 1
src/screens/InAppScreens/MessagesScreen/index.tsx

@@ -1,5 +1,14 @@
 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,
+  AppState,
+  AppStateStatus
+} from 'react-native';
 import {
   AvatarWithInitials,
   HorizontalTabView,
@@ -76,6 +85,8 @@ const MessagesScreen = () => {
   const { isWarningModalVisible, setIsWarningModalVisible } = useChatStore();
   const [typingUsers, setTypingUsers] = useState<{ [key: string]: boolean }>({});
 
+  const appState = useRef(AppState.currentState);
+
   const socket = useRef<WebSocket | null>(null);
 
   const initializeSocket = () => {
@@ -101,10 +112,46 @@ const MessagesScreen = () => {
     }, 500);
   };
 
+  useEffect(() => {
+    const handleAppStateChange = (nextAppState: AppStateStatus) => {
+      if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
+        if (!socket.current || socket.current.readyState === WebSocket.CLOSED) {
+          socket.current = new WebSocket(WEBSOCKET_URL);
+          socket.current.onopen = () => {
+            socket.current?.send(JSON.stringify({ token }));
+          };
+          socket.current.onmessage = (event) => {
+            const data = JSON.parse(event.data);
+            handleWebSocketMessage(data);
+          };
+        }
+      }
+    };
+
+    const subscription = AppState.addEventListener('change', handleAppStateChange);
+
+    return () => {
+      subscription.remove();
+      if (socket.current) {
+        socket.current.close();
+        socket.current = null;
+      }
+    };
+  }, [token]);
+
   useEffect(() => {
     const pingInterval = setInterval(() => {
       if (socket.current && socket.current.readyState === WebSocket.OPEN) {
         socket.current.send(JSON.stringify({ action: 'ping', conversation_with: 0 }));
+      } else {
+        initializeSocket();
+
+        return () => {
+          if (socket.current) {
+            socket.current.close();
+            socket.current = null;
+          }
+        };
       }
     }, 50000);