Selaa lähdekoodia

unreact in 2 steps

Viktoriia 8 kuukautta sitten
vanhempi
commit
992b6fb54c

+ 25 - 36
src/screens/InAppScreens/MessagesScreen/ChatScreen/index.tsx

@@ -51,8 +51,7 @@ import {
   usePostGetChatWithQuery,
   usePostMessagesReadMutation,
   usePostReactToMessageMutation,
-  usePostSendMessageMutation,
-  usePostUnreactToMessageMutation
+  usePostSendMessageMutation
 } from '@api/chat';
 import { CustomMessage, Message, Reaction } from '../types';
 import { API_HOST, WEBSOCKET_URL } from 'src/constants';
@@ -66,6 +65,7 @@ import { SheetManager } from 'react-native-actions-sheet';
 import { NAVIGATION_PAGES } from 'src/types';
 import * as Notifications from 'expo-notifications';
 import { usePushNotification } from 'src/contexts/PushNotificationContext';
+import ReactionsListModal from '../Components/ReactionsListModal';
 
 const options = {
   enableVibrateFallback: true,
@@ -112,7 +112,6 @@ const ChatScreen = ({ route }: { route: any }) => {
   const { mutateAsync: markMessagesAsRead } = usePostMessagesReadMutation();
   const { mutateAsync: deleteMessage } = usePostDeleteMessageMutation();
   const { mutateAsync: reactToMessage } = usePostReactToMessageMutation();
-  const { mutateAsync: unreactToMessage } = usePostUnreactToMessageMutation();
 
   const [highlightedMessageId, setHighlightedMessageId] = useState<number | null>(null);
   const [isRerendering, setIsRerendering] = useState<boolean>(false);
@@ -502,32 +501,21 @@ const ChatScreen = ({ route }: { route: any }) => {
     closeEmojiSelector();
   };
 
-  const handleUnreactToMessage = (messageId: number) => {
-    unreactToMessage(
-      {
+  const openReactionList = (
+    reactions: { uid: number; name: string; reaction: string }[],
+    messageId: number
+  ) => {
+    SheetManager.show('reactions-list-modal', {
+      payload: {
+        users: reactions,
+        currentUserId: +currentUserId,
         token,
-        message_id: messageId,
-        conversation_with_user: id
-      },
-      {
-        onSuccess: () => {
-          setMessages((prevMessages) =>
-            prevMessages?.map((msg) => {
-              if (msg._id === messageId) {
-                return {
-                  ...msg,
-                  reactions: Array.isArray(msg.reactions)
-                    ? msg.reactions.filter((r) => r.uid !== +currentUserId)
-                    : []
-                };
-              }
-              return msg;
-            })
-          );
-          sendWebSocketMessage('new_reaction');
-        }
-      }
-    );
+        messageId,
+        conversation_with_user: id,
+        setMessages,
+        sendWebSocketMessage
+      } as any
+    });
   };
 
   const renderTimeContainer = (time: TimeProps<CustomMessage>) => {
@@ -579,26 +567,26 @@ const ChatScreen = ({ route }: { route: any }) => {
                 : []
               ).reduce(
                 (
-                  acc: Record<string, { count: number; uids: number[] }>,
+                  acc: Record<
+                    string,
+                    { count: number; users: { uid: number; name: string; reaction: string }[] }
+                  >,
                   { reaction, uid }: { reaction: string; uid: number }
                 ) => {
                   if (!acc[reaction]) {
-                    acc[reaction] = { count: 0, uids: [] };
+                    acc[reaction] = { count: 0, users: [] };
                   }
                   acc[reaction].count += 1;
-                  acc[reaction].uids.push(uid);
+                  acc[reaction].users.push({ uid, name: uid === id ? name : 'Me', reaction });
                   return acc;
                 },
                 {}
               )
-            ).map(([emoji, { count, uids }]: any) => {
-              const isUserReacted = uids.includes(+currentUserId);
-
+            ).map(([emoji, { count, users }]: any) => {
               return (
                 <TouchableOpacity
                   key={emoji}
-                  onPress={() => handleUnreactToMessage(time.currentMessage._id)}
-                  disabled={!isUserReacted}
+                  onPress={() => openReactionList(users, time.currentMessage._id)}
                 >
                   <Text style={{}}>
                     {emoji}
@@ -1311,6 +1299,7 @@ const ChatScreen = ({ route }: { route: any }) => {
             closeModal();
           }}
         />
+        <ReactionsListModal />
       </GestureHandlerRootView>
       <View
         style={{

+ 138 - 0
src/screens/InAppScreens/MessagesScreen/Components/ReactionsListModal.tsx

@@ -0,0 +1,138 @@
+import React, { useState } from 'react';
+import { View, Text, TouchableOpacity, FlatList, StyleSheet } from 'react-native';
+import ActionSheet, { SheetManager } from 'react-native-actions-sheet';
+import { usePostUnreactToMessageMutation } from '@api/chat';
+import { getFontSize } from 'src/utils';
+import { Colors } from 'src/theme';
+
+const ReactionsListModal = () => {
+  const [reactionsData, setReactionsData] = useState<{
+    users: { uid: number; name: string; reaction: string }[];
+    currentUserId: number;
+    token: string;
+    messageId: number;
+    conversation_with_user: number;
+    setMessages: (messages: any) => void;
+    sendWebSocketMessage: (message: string) => void;
+  } | null>(null);
+
+  const { mutateAsync: unreactToMessage } = usePostUnreactToMessageMutation();
+
+  const handleSheetOpen = (
+    payload: {
+      users: { uid: number; name: string; reaction: string }[];
+      currentUserId: number;
+      token: string;
+      messageId: number;
+      conversation_with_user: number;
+      setMessages: (messages: any) => void;
+      sendWebSocketMessage: (message: string) => void;
+    } | null
+  ) => {
+    setReactionsData(payload);
+  };
+
+  const handleUnreact = () => {
+    if (reactionsData) {
+      unreactToMessage(
+        {
+          token: reactionsData.token,
+          message_id: reactionsData.messageId,
+          conversation_with_user: reactionsData.conversation_with_user
+        },
+        {
+          onSuccess: () => {
+            SheetManager.hide('reactions-list-modal');
+            reactionsData.setMessages((prevMessages: any) =>
+              prevMessages?.map((msg: any) => {
+                if (msg._id === reactionsData.messageId) {
+                  return {
+                    ...msg,
+                    reactions: Array.isArray(msg.reactions)
+                      ? msg.reactions.filter((r: any) => r.uid !== reactionsData.currentUserId)
+                      : []
+                  };
+                }
+                return msg;
+              })
+            );
+            reactionsData.sendWebSocketMessage('new_reaction');
+          }
+        }
+      );
+    }
+  };
+
+  return (
+    <ActionSheet
+      id="reactions-list-modal"
+      gestureEnabled={true}
+      onBeforeShow={(sheetRef) => {
+        const payload = sheetRef || null;
+        handleSheetOpen(payload);
+      }}
+      containerStyle={styles.sheetContainer}
+      defaultOverlayOpacity={0.5}
+      indicatorStyle={{ backgroundColor: Colors.FILL_LIGHT }}
+    >
+      <View style={styles.container}>
+        <FlatList
+          data={reactionsData?.users || []}
+          keyExtractor={(item) => item.uid.toString()}
+          renderItem={({ item }) => {
+            const isUserReacted = item.uid === reactionsData?.currentUserId;
+            return (
+              <TouchableOpacity
+                style={styles.userItem}
+                onPress={handleUnreact}
+                disabled={!isUserReacted}
+              >
+                <View style={{}}>
+                  <Text style={styles.userName}>{item.name}</Text>
+                  {isUserReacted && <Text style={styles.unreactText}>Tap to unreact</Text>}
+                </View>
+                <Text style={styles.reaction}>{item.reaction}</Text>
+              </TouchableOpacity>
+            );
+          }}
+        />
+      </View>
+    </ActionSheet>
+  );
+};
+
+const styles = StyleSheet.create({
+  sheetContainer: {
+    borderTopLeftRadius: 15,
+    borderTopRightRadius: 15,
+    padding: 16,
+    paddingTop: 0,
+    height: '40%'
+  },
+  container: {
+    paddingTop: 12
+  },
+  userItem: {
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    alignItems: 'center',
+    paddingVertical: 12,
+    borderBottomWidth: 1,
+    borderBottomColor: Colors.FILL_LIGHT
+  },
+  userName: {
+    fontSize: getFontSize(14),
+    color: Colors.DARK_BLUE,
+    fontFamily: 'montserrat-600'
+  },
+  reaction: {
+    fontSize: 20
+  },
+  unreactText: {
+    color: Colors.LIGHT_GRAY,
+    fontSize: getFontSize(12),
+    fontWeight: '600'
+  }
+});
+
+export default ReactionsListModal;