Przeglądaj źródła

chat store + delete chat func

Viktoriia 8 miesięcy temu
rodzic
commit
ec2b6700c2

+ 30 - 19
src/screens/InAppScreens/MessagesScreen/Components/MoreModal.tsx

@@ -1,6 +1,6 @@
 import React, { useState } from 'react';
 import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native';
-import ActionSheet from 'react-native-actions-sheet';
+import ActionSheet, { SheetManager } from 'react-native-actions-sheet';
 import { Colors } from 'src/theme';
 import { Ionicons } from '@expo/vector-icons';
 import { API_HOST } from 'src/constants';
@@ -9,25 +9,32 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
 import { ChatProps } from '../types';
 import { useNavigation } from '@react-navigation/native';
 import { NAVIGATION_PAGES } from 'src/types';
-import {
-  usePostDeleteChatMutation,
-  usePostSetBlockMutation,
-  usePostSetMuteMutation
-} from '@api/chat';
+import { usePostSetBlockMutation, usePostSetMuteMutation } from '@api/chat';
+import { useChatStore } from 'src/stores/chatStore';
 
 const MoreModal = () => {
   const insets = useSafeAreaInsets();
   const navigation = useNavigation();
+  const { setIsWarningModalVisible } = useChatStore();
 
   const [chatData, setChatData] = useState<
-    (ChatProps & { token: string; refetch: () => void }) | null
+    | (ChatProps & {
+        token: string;
+        refetch: () => void;
+      })
+    | null
   >(null);
   const { mutateAsync: muteUser } = usePostSetMuteMutation();
   const { mutateAsync: blockUser } = usePostSetBlockMutation();
-  const { mutateAsync: deleteChat } = usePostDeleteChatMutation();
+  const [shouldOpenWarningModal, setShouldOpenWarningModal] = useState(false);
 
   const handleSheetOpen = (
-    payload: (ChatProps & { token: string; refetch: () => void }) | null
+    payload:
+      | (ChatProps & {
+          token: string;
+          refetch: () => void;
+        })
+      | null
   ) => {
     setChatData(payload);
   };
@@ -39,7 +46,7 @@ const MoreModal = () => {
       {
         token: chatData.token,
         value: chatData.muted === 1 ? 0 : 1,
-        conversation_with_user: chatData.id
+        conversation_with_user: chatData.uid
       },
       {
         onSuccess: () => {
@@ -52,20 +59,19 @@ const MoreModal = () => {
 
   const handleBlock = async () => {
     // if (!chatData) return;
-    
     // await blockUser({
     //   value: chatData.blocked === 1 ? 0 : 1,
-    //   conversation_with_user: chatData.id
+    //   conversation_with_user: chatData.uid
     // });
   };
 
   const handleDelete = async () => {
-    if (!chatData) return;
+    setShouldOpenWarningModal(true);
 
-    await deleteChat({
-      token: chatData.token,
-      conversation_with_user: chatData.id
-    });
+    setTimeout(() => {
+      SheetManager.hide('more-modal');
+      setShouldOpenWarningModal(false);
+    }, 300);
   };
 
   return (
@@ -76,6 +82,11 @@ const MoreModal = () => {
         const payload = sheetRef || null;
         handleSheetOpen(payload);
       }}
+      onClose={() => {
+        if (shouldOpenWarningModal) {
+          setIsWarningModalVisible(true);
+        }
+      }}
       containerStyle={styles.sheetContainer}
       defaultOverlayOpacity={0.5}
       indicatorStyle={{ backgroundColor: 'transparent' }}
@@ -86,7 +97,7 @@ const MoreModal = () => {
             style={styles.header}
             onPress={() =>
               navigation.navigate(
-                ...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId: chatData.id }] as never)
+                ...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId: chatData.uid }] as never)
               )
             }
           >
@@ -107,7 +118,7 @@ const MoreModal = () => {
               <Ionicons name="ban-outline" size={18} color={Colors.RED} />
             </TouchableOpacity>
 
-            <TouchableOpacity style={[styles.option, styles.dangerOption]}>
+            <TouchableOpacity style={[styles.option, styles.dangerOption]} onPress={handleDelete}>
               <Text style={[styles.optionText, styles.dangerText]}>Delete chat</Text>
               <Ionicons name="trash-outline" size={18} color={Colors.RED} />
             </TouchableOpacity>

+ 7 - 4
src/screens/InAppScreens/MessagesScreen/Components/SwipeableRow.tsx

@@ -11,6 +11,7 @@ import DotsIcon from 'assets/icons/messages/dots.svg';
 import UnpinIcon from 'assets/icons/messages/unpin.svg';
 import { ChatProps } from '../types';
 import { usePostSetArchiveMutation, usePostSetPinMutation } from '@api/chat';
+import { useChatStore } from 'src/stores/chatStore';
 
 interface AppleStyleSwipeableRowProps extends PropsWithChildren<unknown> {
   chat: ChatProps;
@@ -27,6 +28,7 @@ const SwipeableRow: React.FC<AppleStyleSwipeableRowProps> = ({
   refetch
 }) => {
   const swipeableRow = useRef<Swipeable>(null);
+  const { setSelectedChat } = useChatStore();
 
   const { mutateAsync: pinChat } = usePostSetPinMutation();
   const { mutateAsync: archiveChat } = usePostSetArchiveMutation();
@@ -49,21 +51,22 @@ const SwipeableRow: React.FC<AppleStyleSwipeableRowProps> = ({
     const pressHandler = async () => {
       close();
       if (text === 'More') {
+        setSelectedChat(chat);
         SheetManager.show('more-modal', {
           payload: {
-            id: chat.id,
+            uid: chat.uid,
             name: chat.name,
             avatar: chat.avatar,
             mute: chat.muted,
             token: token,
-            refetch
+            refetch,
           } as any
         });
       } else {
         await archiveChat({
           token,
           value: chat.archive === 1 ? 0 : 1,
-          conversation_with_user: chat.id
+          conversation_with_user: chat.uid
         });
         refetch();
       }
@@ -99,7 +102,7 @@ const SwipeableRow: React.FC<AppleStyleSwipeableRowProps> = ({
       await pinChat({
         token,
         value: chat.pin === 1 ? 0 : 1,
-        conversation_with_user: chat.id
+        conversation_with_user: chat.uid
       });
       refetch();
     };

+ 7 - 0
src/screens/InAppScreens/MessagesScreen/constants.ts

@@ -0,0 +1,7 @@
+import { Routes } from "./types";
+
+export const routes: Routes[] = [
+  { key: 'all', title: 'All' },
+  { key: 'unread', title: 'Unread' },
+  { key: 'archived', title: 'Archived' }
+];

+ 37 - 139
src/screens/InAppScreens/MessagesScreen/index.tsx

@@ -1,21 +1,12 @@
 import React, { useState, useEffect, useRef, useCallback } from 'react';
-import {
-  View,
-  Text,
-  TouchableOpacity,
-  StyleSheet,
-  Image,
-  Platform,
-  TouchableHighlight
-} from 'react-native';
-import { HorizontalTabView, Input, PageWrapper } from 'src/components';
+import { View, Text, TouchableOpacity, Image, Platform, TouchableHighlight } from 'react-native';
+import { HorizontalTabView, Input, PageWrapper, WarningModal } from 'src/components';
 import { NAVIGATION_PAGES } from 'src/types';
 import { useFocusEffect, useNavigation } from '@react-navigation/native';
 
 import AddChatIcon from 'assets/icons/messages/chat-plus.svg';
 import { API_HOST } from 'src/constants';
 import { Colors } from 'src/theme';
-import { getFontSize } from 'src/utils';
 import SwipeableRow from './Components/SwipeableRow';
 import { FlashList } from '@shopify/flash-list';
 
@@ -26,16 +17,14 @@ import { SheetManager } from 'react-native-actions-sheet';
 import MoreModal from './Components/MoreModal';
 import SearchIcon from 'assets/icons/search.svg';
 import { storage, StoreType } from 'src/storage';
-import { usePostGetChatsListQuery } from '@api/chat';
-import moment from 'moment';
+import { usePostDeleteChatMutation, usePostGetChatsListQuery } from '@api/chat';
 import { Chat } from './types';
 
 import PinIcon from 'assets/icons/messages/pin.svg';
-
-type Routes = {
-  key: 'all' | 'unread' | 'archived';
-  title: string;
-};
+import { formatDate } from './utils';
+import { routes } from './constants';
+import { styles } from './styles';
+import { useChatStore } from 'src/stores/chatStore';
 
 const MessagesScreen = () => {
   const navigation = useNavigation();
@@ -43,15 +32,13 @@ const MessagesScreen = () => {
   const [chats, setChats] = useState<Chat[]>([]);
   const [index, setIndex] = useState(0);
   const { data: chatsData, refetch } = usePostGetChatsListQuery(token, index === 2 ? 1 : 0, true);
+
   const [filteredChats, setFilteredChats] = useState<Chat[]>([]);
   const [search, setSearch] = useState('');
+  const { mutateAsync: deleteChat } = usePostDeleteChatMutation();
   const openRowRef = useRef<any>(null);
-
-  const routes: Routes[] = [
-    { key: 'all', title: 'All' },
-    { key: 'unread', title: 'Unread' },
-    { key: 'archived', title: 'Archived' }
-  ];
+  const { isWarningModalVisible, setIsWarningModalVisible, selectedChat, setSelectedChat } =
+    useChatStore();
 
   const handleRowOpen = (ref: any) => {
     if (openRowRef.current && openRowRef.current !== ref) {
@@ -86,30 +73,30 @@ const MessagesScreen = () => {
   );
 
   const filterChatsByTab = () => {
+    let filteredList = chats;
+
     if (index === 1) {
-      setFilteredChats(
-        chats
-          .filter((chat: Chat) => chat.unread_count > 0)
-          .sort((a: Chat, b: Chat) => b.pin - a.pin || b.pin_order - a.pin_order)
-      );
-    } else if (index === 2) {
-      setFilteredChats(
-        chats.sort((a: Chat, b: Chat) => b.pin - a.pin || b.pin_order - a.pin_order)
-      );
-    } else {
-      setFilteredChats(
-        chats.sort((a: Chat, b: Chat) => b.pin - a.pin || b.pin_order - a.pin_order)
-      );
+      filteredList = chats.filter((chat) => chat.unread_count > 0);
     }
+
+    filteredList.sort((a, b) => b.pin - a.pin || b.pin_order - a.pin_order);
+    setFilteredChats(filteredList);
   };
 
   useEffect(() => {
     filterChatsByTab();
-  }, [index, chats]);
+  }, [chats, index]);
+
+  const handleDeleteChat = async () => {
+    if (!selectedChat) return;
 
-  const handleDeleteChat = (id: number) => {
-    const updatedChats = chats.filter((chat: Chat) => chat.uid !== id);
-    setChats(updatedChats);
+    await deleteChat({
+      token: token,
+      conversation_with_user: selectedChat.uid
+    });
+
+    refetch();
+    setSelectedChat(null);
   };
 
   const searchFilter = (text: string) => {
@@ -128,32 +115,11 @@ const MessagesScreen = () => {
     }
   };
 
-  const formatDate = (dateString: Date) => {
-    const inputDate = moment.utc(dateString).local();
-    const today = moment().local();
-
-    const yesterday = moment().local().subtract(1, 'days');
-
-    if (inputDate.isSame(today, 'day')) {
-      return inputDate.format('HH:mm');
-    }
-
-    if (inputDate.isSame(yesterday, 'day')) {
-      return 'yesterday';
-    }
-
-    if (!inputDate.isSame(today, 'year')) {
-      return inputDate.format('DD.MM.YYYY');
-    }
-
-    return inputDate.format('DD.MM');
-  };
-
   const renderChatItem = ({ item }: { item: Chat }) => {
     return (
       <SwipeableRow
         chat={{
-          id: item.uid,
+          uid: item.uid,
           name: item.name,
           avatar: item.avatar,
           pin: item.pin,
@@ -265,84 +231,16 @@ const MessagesScreen = () => {
 
       <SearchModal />
       <MoreModal />
+      <WarningModal
+        type={'delete'}
+        isVisible={isWarningModalVisible}
+        onClose={() => setIsWarningModalVisible(false)}
+        title="Delete conversation"
+        message={`Are you sure you want to delete conversation with ${selectedChat?.name}?\nThis conversation will be deleted for both sides.`}
+        action={handleDeleteChat}
+      />
     </PageWrapper>
   );
 };
 
-const styles = StyleSheet.create({
-  title: { color: Colors.DARK_BLUE, fontFamily: 'redhat-700', fontSize: getFontSize(14) },
-  header: {
-    alignItems: 'center',
-    paddingVertical: 16,
-    flexDirection: 'row',
-    justifyContent: 'space-between',
-    marginLeft: '5%',
-    marginRight: '5%'
-  },
-  chatItem: {
-    flexDirection: 'row',
-    paddingVertical: 12,
-    backgroundColor: Colors.WHITE,
-    borderBottomWidth: 1,
-    borderBottomColor: Colors.FILL_LIGHT,
-    gap: 8,
-    paddingHorizontal: '4%'
-  },
-  avatar: {
-    width: 54,
-    height: 54,
-    borderRadius: 27,
-    borderWidth: 1,
-    borderColor: Colors.FILL_LIGHT
-  },
-  rowContainer: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'space-between'
-  },
-  chatName: {
-    flex: 1,
-    fontFamily: 'montserrat-700',
-    fontSize: getFontSize(14),
-    color: Colors.DARK_BLUE
-  },
-  chatMessage: {
-    flex: 1,
-    fontSize: getFontSize(12),
-    fontWeight: '600',
-    color: Colors.DARK_BLUE,
-    height: '100%'
-  },
-  chatTimeContainer: {
-    justifyContent: 'center',
-    alignItems: 'flex-end'
-  },
-  chatTime: {
-    fontSize: getFontSize(12),
-    fontWeight: '600',
-    color: Colors.LIGHT_GRAY
-  },
-  unreadBadge: {
-    backgroundColor: Colors.ORANGE,
-    borderRadius: 9,
-    paddingHorizontal: 6,
-    alignItems: 'center',
-    justifyContent: 'center',
-    height: 18,
-    minWidth: 18
-  },
-  unreadText: {
-    color: Colors.WHITE,
-    fontSize: getFontSize(11),
-    fontFamily: 'montserrat-700'
-  },
-  swipeActions: {
-    flexDirection: 'row',
-    alignItems: 'center'
-  },
-  swipeButton: {
-    paddingHorizontal: 20
-  }
-});
-
 export default MessagesScreen;

+ 79 - 0
src/screens/InAppScreens/MessagesScreen/styles.tsx

@@ -0,0 +1,79 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'src/theme';
+import { getFontSize } from 'src/utils';
+
+export const styles = StyleSheet.create({
+  title: { color: Colors.DARK_BLUE, fontFamily: 'redhat-700', fontSize: getFontSize(14) },
+  header: {
+    alignItems: 'center',
+    paddingVertical: 16,
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    marginLeft: '5%',
+    marginRight: '5%'
+  },
+  chatItem: {
+    flexDirection: 'row',
+    paddingVertical: 12,
+    backgroundColor: Colors.WHITE,
+    borderBottomWidth: 1,
+    borderBottomColor: Colors.FILL_LIGHT,
+    gap: 8,
+    paddingHorizontal: '4%'
+  },
+  avatar: {
+    width: 54,
+    height: 54,
+    borderRadius: 27,
+    borderWidth: 1,
+    borderColor: Colors.FILL_LIGHT
+  },
+  rowContainer: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-between'
+  },
+  chatName: {
+    flex: 1,
+    fontFamily: 'montserrat-700',
+    fontSize: getFontSize(14),
+    color: Colors.DARK_BLUE
+  },
+  chatMessage: {
+    flex: 1,
+    fontSize: getFontSize(12),
+    fontWeight: '600',
+    color: Colors.DARK_BLUE,
+    height: '100%'
+  },
+  chatTimeContainer: {
+    justifyContent: 'center',
+    alignItems: 'flex-end'
+  },
+  chatTime: {
+    fontSize: getFontSize(12),
+    fontWeight: '600',
+    color: Colors.LIGHT_GRAY
+  },
+  unreadBadge: {
+    backgroundColor: Colors.ORANGE,
+    borderRadius: 9,
+    paddingHorizontal: 6,
+    alignItems: 'center',
+    justifyContent: 'center',
+    height: 18,
+    minWidth: 18
+  },
+  unreadText: {
+    color: Colors.WHITE,
+    fontSize: getFontSize(11),
+    fontFamily: 'montserrat-700'
+  },
+  swipeActions: {
+    flexDirection: 'row',
+    alignItems: 'center'
+  },
+  swipeButton: {
+    paddingHorizontal: 20
+  }
+});

+ 6 - 1
src/screens/InAppScreens/MessagesScreen/types.ts

@@ -20,7 +20,7 @@ export type Chat = {
 };
 
 export type ChatProps = {
-  id: number;
+  uid: number;
   name: string;
   avatar: string | null;
   pin: 0 | 1;
@@ -65,3 +65,8 @@ export type Reaction = {
   reaction: string;
   uid: number;
 };
+
+export type Routes = {
+  key: 'all' | 'unread' | 'archived';
+  title: string;
+};

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

@@ -0,0 +1,19 @@
+import moment from 'moment';
+
+export const formatDate = (dateString: Date): string => {
+  const inputDate = moment.utc(dateString).local();
+  const today = moment().local();
+  const yesterday = moment().local().subtract(1, 'days');
+
+  if (inputDate.isSame(today, 'day')) {
+    return inputDate.format('HH:mm');
+  }
+  if (inputDate.isSame(yesterday, 'day')) {
+    return 'yesterday';
+  }
+  if (!inputDate.isSame(today, 'year')) {
+    return inputDate.format('DD.MM.YYYY');
+  }
+
+  return inputDate.format('DD.MM');
+};

+ 16 - 0
src/stores/chatStore.ts

@@ -0,0 +1,16 @@
+import { create } from 'zustand';
+import { ChatProps } from 'src/screens/InAppScreens/MessagesScreen/types';
+
+interface ChatStore {
+  selectedChat: ChatProps | null;
+  setSelectedChat: (chat: ChatProps | null) => void;
+  isWarningModalVisible: boolean;
+  setIsWarningModalVisible: (value: boolean) => void;
+}
+
+export const useChatStore = create<ChatStore>((set) => ({
+  selectedChat: null,
+  setSelectedChat: (chat) => set({ selectedChat: chat }),
+  isWarningModalVisible: false,
+  setIsWarningModalVisible: (value) => set({ isWarningModalVisible: value })
+}));

+ 1 - 1
src/types/api.ts

@@ -137,7 +137,7 @@ export enum API_ENDPOINT {
   SET_ARCHIVE = 'set-archive',
   SET_BLOCK = 'set-block',
   SET_MUTE = 'set-mute',
-  DELETE_CHAT = 'delete-chat'
+  DELETE_CHAT = 'delete-conversation'
 }
 
 export enum API {