Browse Source

emoji selector refactor

Viktoriia 8 months ago
parent
commit
965051b92a

+ 10 - 0
assets/icons/messages/ban.svg

@@ -0,0 +1,10 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_4126_37135)">
+<path d="M12.9094 14.502L3.49805 5.09063C2.71055 6.19102 2.25 7.54102 2.25 9C2.25 12.7266 5.27344 15.75 9 15.75C10.459 15.75 11.809 15.2895 12.9094 14.502ZM14.502 12.9094C15.2895 11.809 15.75 10.459 15.75 9C15.75 5.27344 12.7266 2.25 9 2.25C7.54102 2.25 6.19102 2.71055 5.09063 3.49805L14.502 12.9094ZM0 9C0 6.61305 0.948212 4.32387 2.63604 2.63604C4.32387 0.948212 6.61305 0 9 0C11.3869 0 13.6761 0.948212 15.364 2.63604C17.0518 4.32387 18 6.61305 18 9C18 11.3869 17.0518 13.6761 15.364 15.364C13.6761 17.0518 11.3869 18 9 18C6.61305 18 4.32387 17.0518 2.63604 15.364C0.948212 13.6761 0 11.3869 0 9Z" fill="#EF5B5B"/>
+</g>
+<defs>
+<clipPath id="clip0_4126_37135">
+<rect width="18" height="18" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 10 - 0
assets/icons/messages/bell-slash.svg

@@ -0,0 +1,10 @@
+<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_4126_37122)">
+<path d="M1.09141 0.944377C0.798908 0.713752 0.374221 0.767189 0.143596 1.05969C-0.0870294 1.35219 -0.0335919 1.77688 0.258908 2.0075L16.9089 15.0575C17.2014 15.2881 17.6261 15.2347 17.8567 14.9422C18.0873 14.6497 18.0339 14.225 17.7414 13.9944L15.2608 12.0509C15.3367 11.8316 15.2973 11.5869 15.1511 11.4041L14.732 10.8809C13.9361 9.8825 13.5002 8.64219 13.5002 7.36531V6.42594C13.5002 4.29406 11.9392 2.52781 9.90016 2.20438V1.70094C9.90016 1.20313 9.49797 0.800939 9.00016 0.800939C8.50235 0.800939 8.10016 1.20313 8.10016 1.70094V2.20438C6.86547 2.40125 5.80797 3.12406 5.16391 4.13656L1.09141 0.944377ZM6.23547 4.97469C6.73891 4.09438 7.68672 3.50094 8.77516 3.50094H9.00016H9.22516C10.8395 3.50094 12.1502 4.81156 12.1502 6.42594V7.36531C12.1502 8.285 12.3302 9.18781 12.6761 10.0231L6.23547 4.97469ZM11.4245 12.5009L9.71172 11.1509H4.73641C5.33266 10.2284 5.70391 9.17375 5.81641 8.0825L4.50016 7.0475V7.36813C4.50016 8.645 4.06422 9.88531 3.26828 10.8809L2.84922 11.4041C2.6861 11.6066 2.65516 11.885 2.76766 12.1184C2.88016 12.3519 3.11641 12.5009 3.37516 12.5009H11.4245ZM10.8002 13.4009H9.00016H7.20016C7.20016 13.8791 7.3886 14.3375 7.7261 14.675C8.0636 15.0125 8.52203 15.2009 9.00016 15.2009C9.47828 15.2009 9.93672 15.0125 10.2742 14.675C10.6117 14.3375 10.8002 13.8791 10.8002 13.4009Z" fill="#0F3F4F"/>
+</g>
+<defs>
+<clipPath id="clip0_4126_37122">
+<rect width="18" height="14.4" fill="white" transform="translate(0 0.800781)"/>
+</clipPath>
+</defs>
+</svg>

+ 10 - 0
assets/icons/messages/send.svg

@@ -0,0 +1,10 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_4211_36895)">
+<path d="M17.5117 0.197009C17.8668 0.443103 18.0531 0.868494 17.9863 1.29388L15.7363 15.9189C15.6836 16.2599 15.4761 16.5587 15.1738 16.7275C14.8715 16.8962 14.5094 16.9173 14.1894 16.7837L9.98474 15.0365L7.57654 17.6415C7.26365 17.9826 6.77146 18.0951 6.33904 17.9263C5.90662 17.7576 5.62537 17.3392 5.62537 16.8751V13.9361C5.62537 13.7954 5.6781 13.6619 5.77302 13.5564L11.6652 7.12982C11.8691 6.90834 11.8621 6.56732 11.6511 6.35638C11.4402 6.14545 11.0992 6.13138 10.8777 6.33178L3.72693 12.6845L0.622632 11.1306C0.249976 10.9443 0.010913 10.5716 0.000366172 10.1568C-0.0101807 9.74193 0.207788 9.35521 0.566382 9.14779L16.3164 0.147791C16.6926 -0.0666624 17.1566 -0.0455687 17.5117 0.197009Z"/>
+</g>
+<defs>
+<clipPath id="clip0_4211_36895">
+<rect width="18" height="18" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 20 - 22
src/screens/InAppScreens/MessagesScreen/ChatScreen/index.tsx

@@ -8,7 +8,8 @@ import {
   FlatList,
   Dimensions,
   Alert,
-  ScrollView
+  ScrollView,
+  Linking
 } from 'react-native';
 import {
   GiftedChat,
@@ -57,6 +58,8 @@ import ReactionBar from '../Components/ReactionBar';
 import OptionsMenu from '../Components/OptionsMenu';
 import EmojiSelectorModal from '../Components/EmojiSelectorModal';
 import { styles } from './styles';
+import SendIcon from 'assets/icons/messages/send.svg';
+import { SheetManager } from 'react-native-actions-sheet';
 
 const options = {
   enableVibrateFallback: true,
@@ -247,12 +250,12 @@ const ChatScreen = ({ route }: { route: any }) => {
   };
 
   const openEmojiSelector = () => {
-    setEmojiSelectorVisible(true);
+    SheetManager.show('emoji-selector');
     trigger('impactLight', options);
   };
 
   const closeEmojiSelector = () => {
-    setEmojiSelectorVisible(false);
+    SheetManager.hide('emoji-selector');
   };
 
   const handleReactionPress = (emoji: string, messageId: number) => {
@@ -908,10 +911,9 @@ const ChatScreen = ({ route }: { route: any }) => {
             <View
               style={{
                 flexDirection: 'row',
-                height: 44,
+                height: '100%',
                 alignItems: 'center',
                 justifyContent: 'center',
-                gap: 14,
                 paddingHorizontal: 14
               }}
             >
@@ -922,25 +924,10 @@ const ChatScreen = ({ route }: { route: any }) => {
                     justifyContent: 'center'
                   }}
                 >
-                  <MaterialCommunityIcons name="send" size={28} color={Colors.DARK_BLUE} />
+                  <SendIcon fill={Colors.DARK_BLUE} />
                 </Send>
               )}
-              {!props.text?.trim() && (
-                <>
-                  {/* <MaterialCommunityIcons
-                    name="microphone-outline"
-                    size={28}
-                    color={Colors.DARK_BLUE}
-                  />
-
-                  <MaterialCommunityIcons
-                    name="camera-outline"
-                    size={28}
-                    color={Colors.DARK_BLUE}
-                  /> */}
-                  <MaterialCommunityIcons name="send" size={28} color={Colors.LIGHT_GRAY} />
-                </>
-              )}
+              {!props.text?.trim() && <SendIcon fill={Colors.LIGHT_GRAY} />}
             </View>
           )}
           textInputProps={{ ...styles.composer, selectionColor: Colors.LIGHT_GRAY }}
@@ -966,6 +953,17 @@ const ChatScreen = ({ route }: { route: any }) => {
           scrollToBottom={true}
           scrollToBottomComponent={renderScrollToBottom}
           scrollToBottomStyle={{ backgroundColor: 'transparent' }}
+          parsePatterns={(linkStyle) => [
+            {
+              type: 'url',
+              style: { color: Colors.ORANGE, textDecorationLine: 'underline' },
+              onPress: (url: string) => Linking.openURL(url),
+              onLongPress: (url: string) => {
+                Clipboard.setString(url ?? '');
+                Alert.alert('copied');
+              }
+            }
+          ]}
           // inverted={true}
           // isTyping={true}
         />

+ 1 - 1
src/screens/InAppScreens/MessagesScreen/ChatScreen/styles.tsx

@@ -51,7 +51,7 @@ export const styles = StyleSheet.create({
   composer: {
     backgroundColor: Colors.WHITE,
     borderRadius: 12,
-    borderWidth: 1,
+    borderWidth: 0.5,
     borderColor: Colors.LIGHT_GRAY,
     paddingHorizontal: 10,
     fontSize: 16,

+ 25 - 19
src/screens/InAppScreens/MessagesScreen/Components/EmojiSelectorModal.tsx

@@ -1,9 +1,7 @@
 import React from 'react';
-import { TouchableOpacity, StyleSheet } from 'react-native';
+import { StyleSheet, View } from 'react-native';
 import EmojiSelector from 'react-native-emoji-selector';
-import { MaterialCommunityIcons } from '@expo/vector-icons';
-import Animated, { SlideInDown, SlideOutDown } from 'react-native-reanimated';
-import { Colors } from 'src/theme';
+import ActionSheet from 'react-native-actions-sheet';
 
 interface EmojiSelectorModalProps {
   visible: boolean;
@@ -13,17 +11,27 @@ interface EmojiSelectorModalProps {
 }
 
 const EmojiSelectorModal: React.FC<EmojiSelectorModalProps> = ({
-  visible,
   addReaction,
   selectedMessage,
   closeEmojiSelector
-}) =>
-  visible && (
-    <Animated.View
-      entering={SlideInDown}
-      exiting={SlideOutDown}
-      style={styles.emojiSelectorContainer}
-    >
+}) => (
+  <ActionSheet
+    id="emoji-selector"
+    gestureEnabled={true}
+    containerStyle={{
+      borderTopLeftRadius: 15,
+      borderTopRightRadius: 15,
+      height: '60%',
+      padding: 10
+    }}
+    defaultOverlayOpacity={0.5}
+  >
+    <View style={{ height: '100%', width: '100%', paddingTop: 8 }}>
+      {/* <View style={{ alignItems: 'flex-end' }}>
+        <TouchableOpacity style={{}} onPress={closeEmojiSelector}>
+          <MaterialCommunityIcons name="close" size={28} color={Colors.LIGHT_GRAY} />
+        </TouchableOpacity>
+      </View> */}
       <EmojiSelector
         onEmojiSelected={(emoji) => {
           addReaction(selectedMessage?.currentMessage?._id, emoji);
@@ -32,11 +40,9 @@ const EmojiSelectorModal: React.FC<EmojiSelectorModalProps> = ({
         showSearchBar={true}
         columns={8}
       />
-      <TouchableOpacity style={styles.closeModalButton} onPress={closeEmojiSelector}>
-        <MaterialCommunityIcons name="close" size={30} color={Colors.DARK_BLUE} />
-      </TouchableOpacity>
-    </Animated.View>
-  );
+    </View>
+  </ActionSheet>
+);
 
 const styles = StyleSheet.create({
   emojiSelectorContainer: {
@@ -48,9 +54,9 @@ const styles = StyleSheet.create({
     borderTopLeftRadius: 15,
     borderTopRightRadius: 15,
     shadowColor: '#000',
-    shadowOpacity: 0.3,
+    shadowOpacity: 0.1,
     shadowOffset: { width: 0, height: -2 },
-    shadowRadius: 5,
+    shadowRadius: 4,
     elevation: 5,
     padding: 10
   },

+ 10 - 7
src/screens/InAppScreens/MessagesScreen/Components/MoreModal.tsx

@@ -2,7 +2,6 @@ import React, { useState } from 'react';
 import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native';
 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';
 import { getFontSize } from 'src/utils';
 import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -11,6 +10,9 @@ import { useNavigation } from '@react-navigation/native';
 import { NAVIGATION_PAGES } from 'src/types';
 import { usePostSetBlockMutation, usePostSetMuteMutation } from '@api/chat';
 import { useChatStore } from 'src/stores/chatStore';
+import TrashIcon from 'assets/icons/travels-screens/trash-solid.svg';
+import BanIcon from 'assets/icons/messages/ban.svg';
+import BellSlashIcon from 'assets/icons/messages/bell-slash.svg';
 
 const MoreModal = () => {
   const insets = useSafeAreaInsets();
@@ -95,11 +97,12 @@ const MoreModal = () => {
         <View style={[styles.container, { paddingBottom: 8 + insets.bottom }]}>
           <TouchableOpacity
             style={styles.header}
-            onPress={() =>
+            onPress={() => {
+              SheetManager.hide('more-modal');
               navigation.navigate(
                 ...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId: chatData.uid }] as never)
-              )
-            }
+              );
+            }}
           >
             <Image source={{ uri: API_HOST + chatData?.avatar }} style={styles.avatar} />
             <Text style={styles.name}>{chatData.name}</Text>
@@ -108,19 +111,19 @@ const MoreModal = () => {
           <View style={styles.optionsContainer}>
             <TouchableOpacity style={styles.option} onPress={handleMute}>
               <Text style={styles.optionText}>{chatData.muted === 1 ? 'Unmute' : 'Mute'}</Text>
-              <Ionicons name="notifications-off-outline" size={18} color={Colors.DARK_BLUE} />
+              <BellSlashIcon fill={Colors.DARK_BLUE} />
             </TouchableOpacity>
           </View>
 
           <View style={[styles.optionsContainer, { paddingVertical: 0, gap: 0 }]}>
             <TouchableOpacity style={[styles.option, styles.dangerOption]}>
               <Text style={[styles.optionText, styles.dangerText]}>Block {chatData.name}</Text>
-              <Ionicons name="ban-outline" size={18} color={Colors.RED} />
+              <BanIcon fill={Colors.RED} />
             </TouchableOpacity>
 
             <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} />
+              <TrashIcon fill={Colors.RED} width={18} height={18} />
             </TouchableOpacity>
           </View>
         </View>

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

@@ -33,7 +33,11 @@ const MessagesScreen = () => {
   const [index, setIndex] = useState(0);
   const { data: chatsData, refetch } = usePostGetChatsListQuery(token, index === 2 ? 1 : 0, true);
 
-  const [filteredChats, setFilteredChats] = useState<Chat[]>([]);
+  const [filteredChats, setFilteredChats] = useState<{
+    all: Chat[];
+    unread: Chat[];
+    archived: Chat[];
+  }>({ all: [], unread: [], archived: [] });
   const [search, setSearch] = useState('');
   const { mutateAsync: deleteChat } = usePostDeleteChatMutation();
   const openRowRef = useRef<any>(null);
@@ -80,7 +84,7 @@ const MessagesScreen = () => {
     }
 
     filteredList.sort((a, b) => b.pin - a.pin || b.pin_order - a.pin_order);
-    setFilteredChats(filteredList);
+    setFilteredChats((prev) => ({ ...prev, [routes[index].key]: filteredList }));
   };
 
   useEffect(() => {
@@ -107,7 +111,7 @@ const MessagesScreen = () => {
           const textData = text.toLowerCase();
           return itemData.indexOf(textData) > -1;
         }) ?? [];
-      setFilteredChats(newData);
+      setFilteredChats((prev) => ({ ...prev, [routes[index].key]: newData }));
       setSearch(text);
     } else {
       filterChatsByTab();
@@ -213,18 +217,17 @@ const MessagesScreen = () => {
         setIndex={setIndex}
         routes={routes}
         tabBarStyle={{ paddingHorizontal: '4%' }}
-        renderScene={({ route }: { route: any }) => (
+        renderScene={({ route }: { route: { key: keyof typeof filteredChats } }) => (
           <FlashList
             viewabilityConfig={{
               waitForInteraction: true,
               itemVisiblePercentThreshold: 50,
               minimumViewTime: 1000
             }}
-            data={filteredChats}
+            data={filteredChats[route.key]}
             renderItem={renderChatItem}
             keyExtractor={(item, index) => `${item.uid}-${index}`}
             estimatedItemSize={78}
-            removeClippedSubviews={true}
           />
         )}
       />